테마
RP 활성 헬스 체크 (RP Active Health Check)
1pass IdP 는 등록된 RP 들의 통합이 실제로 살아있는지 주기적으로 확인합니다. 트래픽 기반 시그널(첫 요청 대기 중 / 토큰 발급 통과)은 RP 가 미사용 상태인지 죽은 상태인지 구분할 수 없습니다. 활성 헬스 체크는 IdP 가 직접 RP 의 표준 엔드포인트를 호출해 응답을 검증함으로써 이 모호함을 제거합니다.
핵심
- opt-in 방식: 신규 등록 RP 는 기본 활성, 기존 RP 는 개발자 콘솔에서 토글해 켭니다.
- 매시간 1회 GET
/.well-known/logi-rp-health. - HMAC-SHA256 서명 + client_id echo 검증 + 시계 드리프트 ±5분 검사.
- 결과는 개발자 콘솔 카드 에 🟢 / 🟡 / 🔴 로 표시.
왜 필요한가
| 상황 | 트래픽 기반 시그널 | 활성 헬스 체크 |
|---|---|---|
| 방금 등록한 RP, redirect_uri 오타 | ⏳ 첫 요청 대기 중 (구별 불가) | 🔴 즉시 감지 |
| 배포는 됐는데 OAuth 라우트가 빠짐 | ⏳ 첫 요청 대기 중 | 🔴 즉시 감지 |
| RP cert 만료 | 사용자 클릭 시점에 첫 발견 | 🔴 1시간 안에 감지 |
| 실제로 잘 통합됨 | ⏳ 첫 요청 대기 중 (사용자 없을 때) | 🟢 alive |
| RP 자체가 한가함 (예: 사이드 프로젝트) | ⏳ 첫 요청 대기 중 (영원히) | 🟢 alive (오해 없음) |
프로토콜
요청
IdP 는 다음과 같이 RP 엔드포인트에 GET 요청을 보냅니다:
http
GET /.well-known/logi-rp-health HTTP/1.1
Host: example.com
User-Agent: logi-healthcheck/1.0
Accept: application/json
X-Logi-Timestamp: 1748345678
X-Logi-Client-Id: logi_xxxxxxxxxxxxxxxx
X-Logi-Signature: 7a91...64자 hex...X-Logi-Timestamp: Unix epoch seconds (요청 생성 시각).X-Logi-Client-Id: 검증 대상 client_id.X-Logi-Signature:HMAC-SHA256(secret, "{timestamp}.{client_id}")를 hex 인코딩.secret: RP 가 앱 등록 직후 1회 노출 받은LOGI_RP_HEALTH_SECRET(env 변수로 저장).
RP 측 검증
RP 핸들러는 응답하기 전에 반드시 다음 4가지를 검증해야 합니다:
1. X-Logi-Client-Id == 자신의 등록된 client_id → 다르면 401
2. |now() - X-Logi-Timestamp| ≤ 5분 (300초) → 넘으면 401 (time_drift)
3. constant-time compare:
hex(HMAC-SHA256(LOGI_RP_HEALTH_SECRET,
"{X-Logi-Timestamp}.{X-Logi-Client-Id}"))
== X-Logi-Signature → 다르면 401 (hmac_invalid)
4. (선택) IP 화이트리스트 — 1pass IdP 의 outbound 대역만 허용검증 통과 시 200 OK + JSON body:
json
{
"status": "ok",
"client_id": "logi_xxxxxxxxxxxxxxxx",
"timestamp": "2026-05-27T12:34:56Z",
"sdk_version": "logi-rp-integrate/1.0"
}| 필드 | 필수 | 설명 |
|---|---|---|
status | ✅ | "ok" 또는 "degraded" (RP 가 의도적으로 부분 기능만 가용함을 알리고 싶을 때) |
client_id | ✅ | 반드시 echo. IdP 가 등록값과 strict-match 검증. RP host 가 정말로 이 client_id 와 매핑되었음을 증명. |
timestamp | ✅ | RP 서버 측 ISO 8601 시각. IdP 가 자신의 시각과 비교해 RP 측 시계 드리프트 감지 (>5분 이면 rp_time_drift_Ns 로 기록). |
sdk_version | (선택) | 로그 추적용 |
IdP 측 검증
IdP 는 응답을 다음 순서로 검증합니다:
- HTTP 200 (
Net::HTTPSuccess) — 아니면http_<code>기록. - body 가 JSON parseable — 아니면
body_not_json기록. body.client_id== 등록된client_id— 아니면client_id_mismatch기록.|now() - body.timestamp|≤ 5분 — 아니면rp_time_drift_Ns기록.
모두 통과하면 rp_health_status: healthy 로 전이.
타이밍
- 주기: 매시간 1회 (Render free tier RP 들의 keep-warm 부수효과).
- 타임아웃: open 5초, read 15초 (Render free tier cold start 수용).
- 재시도: 매 ping 당 1회만. 실패 시 다음 시간 ping 까지 기다림.
- 트래픽: 시간당 RP 당 1 req. 11개 RP 기준 264 req/day.
상태 머신
| 상태 | 의미 | 전이 조건 |
|---|---|---|
unknown | 한 번도 핑된 적 없음 (신규 RP 또는 grandfathered) | — (초기값) |
healthy | 직전 핑 성공 | 어느 상태든 1회 성공 |
degraded | 1~2회 연속 실패 | 직전 healthy 였다가 1회 실패, 또는 unknown 에서 실패 |
unreachable | 3회 연속 실패 | 연속 실패 카운터 ≥ 3 |
skipped | 모바일 전용 redirect_uri + health_url 미설정 | redirect_uri 가 deeplink scheme + override URL 없음 |
알림 정책
healthy → unreachable 전이에서만 운영자에게 push 알림이 발화합니다. unknown → unreachable 은 grandfathered RP 의 SDK 미적용 상태와 구별할 수 없으므로 알림 무음 — 핑 결과만 콘솔에 표시됩니다.
모바일 RP (deeplink redirect)
redirect_uri 가 com.example.app://oauth/callback 같은 커스텀 스킴이면 IdP 가 핑할 호스트가 없습니다. 두 가지 처리:
- Backend 가 있는 모바일 RP: 개발자 콘솔의 health endpoint URL 필드에 백엔드 호스트를 입력합니다 (예:
https://api.example.com). IdP 는 항상<health_url>/.well-known/logi-rp-health를 호출합니다. - Backend 가 없는 순수 모바일 RP: health_url 을 비우면
skipped로 자동 마킹. 콘솔에 🔇 표시되고 핑 자체가 발생하지 않습니다.
시크릿 발급 + 회전
- 신규 RP: 등록 직후 개발자 콘솔의 "client_secret 발급 완료" 페이지 에서
LOGI_RP_HEALTH_SECRET도 함께 1회 노출됩니다. - 기존 RP (grandfathered): 개발자 콘솔에서 RP active health check 토글을 켜면 그 순간 시크릿이 신규 발급되고 다음 페이지에서 1회 노출됩니다.
- 회전: 시크릿이 누출되거나 분실됐으면 콘솔의 rotate 버튼으로 즉시 재발급 (기존 시크릿은 즉시 무효화).
보안
LOGI_RP_HEALTH_SECRET은 클라이언트 측 코드에 넣지 마세요. 모바일 앱 / SPA 번들에 포함되면 의미를 잃습니다.- 서버 측 환경 변수 (Render env / Vault / 1Password / AWS Secrets Manager 등) 에만 저장하세요.
통합 예시
스택별 drop-in 코드:
- Rails 8: integrations/rails#health-check-endpoint
- Next.js (App Router): integrations/nextjs#health-check-endpoint
- Express / Node.js: integrations/express#health-check-endpoint
자가 진단
bash
# 자신의 RP 가 헬스 체크에 통과하는지 로컬에서 흉내내기:
TS=$(date +%s)
CID=logi_xxxxxxxxxxxxxxxx
SECRET=$LOGI_RP_HEALTH_SECRET
SIG=$(printf "%s.%s" "$TS" "$CID" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $2}')
curl -i \
-H "User-Agent: logi-healthcheck/1.0" \
-H "X-Logi-Timestamp: $TS" \
-H "X-Logi-Client-Id: $CID" \
-H "X-Logi-Signature: $SIG" \
"https://example.com/.well-known/logi-rp-health"
# 기대: 200 OK
# body.client_id == $CID자주 묻는 질문
헬스 체크가 사용자 데이터에 접근하나요?
아니요. /.well-known/logi-rp-health 는 공개 정적 엔드포인트 입니다. 응답은 client_id, status, timestamp 만 포함하며, 어떤 사용자 정보도 포함하지 않습니다. HMAC 서명은 RP 가 정말로 1pass 와 통합되어 있는지 증명하는 목적만 가집니다 — 트래픽 제한이나 인증 게이트가 아닙니다.
헬스 체크 실패가 자동으로 RP 를 정지시키나요?
아니요. unreachable 상태가 되어도 OAuth 흐름은 정상 동작합니다. 헬스 체크는 관측 도구 일 뿐 enforcement 가 아닙니다. 운영자가 콘솔을 보고 수동으로 판단합니다.
우리 서버 IP 를 1pass 에 알려야 하나요?
선택 사항. RP 측 핸들러가 outbound IP 화이트리스트로 추가 보안을 원할 경우 https://api.1pass.dev/.well-known/outbound-ips (publish 예정) 의 대역만 허용하면 됩니다. 그러나 HMAC 검증만으로도 충분히 안전합니다.
응답에 status: "degraded" 를 보내면 어떻게 되나요?
콘솔에 🟡 로 표시되지만 OAuth 흐름은 그대로 동작합니다. RP 가 "통합은 살아있지만 일부 부분 기능에 문제가 있음" 을 알리고 싶을 때 사용합니다.
모든 RP 가 헬스 엔드포인트를 구현해야 하나요?
신규 등록 RP 는 권장됩니다. 콘솔에서 health_check_enabled 토글을 꺼두면 핑 자체를 받지 않습니다. 모바일 전용 RP 처럼 백엔드 자체가 없는 케이스는 자동으로 skipped 처리됩니다.
관련 문서
- 앱 등록 가이드 —
LOGI_RP_HEALTH_SECRET확보 절차 - Authorization Code Flow — health check 과는 별도의 사용자 인증 흐름
- Public vs Confidential — 두 타입 모두 헬스 체크 시크릿은 동일하게 발급