Skip to content

Dynamic Client Registration (RFC 7591)

RFC 7591 — OAuth 2.0 Dynamic Client Registration Protocol 기반의 server-to-server 등록 엔드포인트입니다. POST /oauth/register 한 번으로 RP 가 콘솔 가입·이메일 인증 없이 public(PKCE-only) OAuth client 를 직접 발급받습니다. claude.ai 같은 MCP connector, CLI, 자율 agent 가 사람이 콘솔을 거치지 않고 스스로 등록할 수 있게 하는 것이 목적입니다.

📋 Confidential RP 는 DCR 대상이 아닙니다

DCR 로 만들어지는 client 는 항상 public 입니다 — client_secret 이 발급되지 않고 PKCE 가 필수입니다. 서버에서 client_secret/oauth/token 에 전달하는 confidential RP(웹 백엔드 등)는 DCR 로 등록할 수 없습니다. confidential 은 콘솔 앱 등록 을 쓰세요. 어느 타입인지 모르겠다면 Public vs Confidential 결정 을 먼저 읽어주세요.

언제 DCR 을 쓰나요?

  • connector / agent 가 자동으로 등록해야 할 때 (claude.ai MCP connector 등 — 사람이 콘솔에 못 들어감)
  • 커스텀 스킴 redirect 를 쓰는 네이티브 / 데스크톱 client (예: myapp://oauth/1pass/callback)
  • CLI 도구 가 설치 시점에 client 를 자체 발급해야 할 때

일반 웹 RP(특히 secret 을 다루는 confidential)는 콘솔 등록 이 더 안전하고 더 넓은 scope 를 받을 수 있습니다.

엔드포인트

POST https://api.1pass.dev/oauth/register
Content-Type: application/json
  • 인증: 기본 unauthenticated (CSRF-skip, host-unlocked — /oauth/token 과 동일한 server-to-server surface). 콘솔 가입이나 이메일 인증 게이트 없이 호출됩니다.
  • 선택적 initial access token: 서버 ENV DCR_REQUIRE_INITIAL_ACCESS_TOKEN 을 켜면 Authorization: Bearer <token> 이 필요해집니다(authenticated DCR). 기본은 미요구. → Initial access token 참고.

이 surface 가 안전한 이유는 인증이 아니라 redirect_uri allowlist + 강제 public 형상 + scope 상한 의 다층 방어 때문입니다(보안 모델 참고).

요청 필드 (RFC 7591 §3.1)

필드필수설명
redirect_uris등록할 redirect URI 배열. 모두 connector allowlist 에 맞아야 함(아래 redirect_uri 제약)
client_name표시용 이름. unauthenticated 등록에서는 무시되고 고정 라벨로 강제됨(consent 화면 위장 방지). authenticated DCR 에서만 반영
scope공백 구분 scope 목록. 상한이 적용됨(scope 상한)
token_endpoint_auth_method받아들이지만 무시 — 응답은 항상 none(public)

요청 본문에 위 외의 client metadata 를 넣어도 조용히 무시됩니다(client 형상은 서버가 강제). grant_types / response_types / client_secret 등은 클라이언트가 지정할 수 없습니다.

응답 (201 Created, RFC 7591 §3.2.1)

json
{
  "client_id": "logi_pub_xxxxxxxxxxxxxxxx",
  "client_id_issued_at": 1717660800,
  "redirect_uris": ["myapp://oauth/1pass/callback"],
  "token_endpoint_auth_method": "none",
  "grant_types": ["authorization_code", "refresh_token"],
  "response_types": ["code"],
  "scope": "openid agent:read agent:write"
}
필드의미
client_id발급된 public client 식별자. 이후 authorize / token 요청에 사용
client_id_issued_at발급 시각(Unix epoch 초)
redirect_uris등록 확정된 redirect URI 목록
token_endpoint_auth_method항상 none — secret 없음
grant_typesauthorization_code, refresh_token 고정
response_typescode 고정
scope실제 허용된 scope 상한(요청값이 아니라 cap 적용 후 값)

client_secret 은 없습니다

public client 이므로 응답에 client_secret / client_secret_expires_at들어있지 않습니다. 토큰 교환은 PKCE(code_verifier)로만 인증합니다. secret 을 기대하는 통합 코드가 있다면 그 RP 는 DCR 대상이 아니라 콘솔 confidential 등록 이 필요합니다.

curl 예시

unauthenticated (기본)

bash
curl -X POST https://api.1pass.dev/oauth/register \
  -H "Content-Type: application/json" \
  -d '{
    "client_name": "My Connector",
    "redirect_uris": ["myapp://oauth/1pass/callback"],
    "scope": "openid"
  }'

# → 201 { "client_id": "...", "token_endpoint_auth_method": "none", ... }
# client_name 은 unauthenticated 라 무시되고 고정 라벨로 등록됩니다.

authenticated (initial access token)

bash
curl -X POST https://api.1pass.dev/oauth/register \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $DCR_INITIAL_ACCESS_TOKEN" \
  -d '{
    "client_name": "My Tool",
    "redirect_uris": ["myapp://oauth/1pass/callback"],
    "scope": "openid agent:tools.invoke"
  }'

발급받은 client_id 로 곧바로 Authorization Code + PKCE Flow 를 시작하면 됩니다.

redirect_uri 제약 (allowlist)

아무 URL 이나 등록되지 않습니다. 요청한 모든 redirect_uris 가 logi 의 connector redirect allowlist 에 맞아야 하며, 하나라도 어긋나면 전체 요청이 invalid_redirect_uri 로 거절됩니다.

  • non-loopback(https 웹 콜백): allowlist 와 정확히 일치해야 함(scheme / host / path / query 모두).
  • loopback(http://localhost, http://127.0.0.1, http://[::1]): RFC 8252 §7.3 에 따라 port 만 유연하게 매칭, scheme · host · path · query 는 정확히 일치해야 함(Claude Desktop 등 데스크톱 client 용).
  • fragment(#...) 가 있는 URI 는 거절됩니다.
  • 커스텀 스킴(myapp://...)은 그 값이 allowlist 에 등록돼 있어야 합니다.

allowlist 는 운영팀이 서버 ENV(CLAUDE_CONNECTOR_REDIRECT_URIS)로 관리합니다. 새 connector / 스킴을 추가하려면 운영팀에 등록을 요청하세요. 이 allowlist 가 DCR 의 핵심 anti-phishing 통제이며, authorize 시점의 redirect 검증과 동일한 출처를 공유합니다.

scope 상한

요청한 scope 는 그대로 부여되지 않고 등록 경로에 따른 상한(ceiling) 으로 잘립니다. 이 값은 client 의 허용 scope 상한 일 뿐이며, 실제 발급되는 토큰의 scope 는 여전히 authorize 시점의 사용자 동의를 거칩니다.

등록 경로보장 baseline추가로 요청 가능받을 수 없음
unauthenticated (기본)openid agent:read agent:write(baseline 외 확장 없음)agent:tools.invoke
authenticated (initial access token)openid agent:read agent:writeagent:tools.invokeallowlist 밖 전부
  • 전체 허용 scope 집합은 openid, agent:read, agent:write, agent:tools.invoke 입니다. 이 밖의 scope(예: profile, email)는 요청해도 조용히 드롭됩니다 — connector 는 신원 프로필 scope 가 필요 없도록 설계돼 있습니다.
  • agent:tools.invoke(도구 실행)는 가장 강력한 권한이라 authenticated DCR 에서만 받을 수 있습니다. unauthenticated 등록은 절대 이 상한을 얻지 못합니다.
  • baseline 이 항상 부여되는 이유: 누군가 allowlist 된 redirect 를 scope=openid 로만 선점해 정식 connector 를 불구로 만드는 것(connector DoS)을 막기 위함입니다.

scope 의 의미와 userinfo 매핑은 Scope 레퍼런스 를 참고하세요.

멱등(idempotent) 재등록

동일한 redirect_uris 집합(SET, 순서 무관) 으로 다시 등록하면 새 client 를 만들지 않고 기존 client 를 그대로 반환합니다(이때 HTTP 상태는 200 OK, 신규 발급은 201 Created).

  • unauthenticated 재등록: 기존 client 를 변경 없이 read-only 로 반환. scope 가 넓어지지 않습니다(선점 client 에 권한을 union 으로 끼워넣는 공격 차단).
  • authenticated 재등록(initial access token): 기존 client 의 scope 를 요청값과 union 으로 WIDEN 가능. 단 상한(ALLOWED_SCOPES) 안에서만.

매칭 대상은 DCR 로 등록된 client 로 한정됩니다(콘솔 등록 client 와 충돌하지 않음).

Initial access token (authenticated DCR)

운영팀이 서버 ENV 로 게이트를 켤 수 있습니다.

ENV의미
DCR_REQUIRE_INITIAL_ACCESS_TOKENtrue 이면 모든 /oauth/register 호출에 Authorization: Bearer <token> 필요
DCR_INITIAL_ACCESS_TOKEN위 게이트가 켜졌을 때 검증할 토큰 값

게이트가 켜진 상태에서 토큰이 없거나 틀리면 401 invalid_token 이 떨어집니다. authenticated 경로에서만 agent:tools.invoke 상한 + 멱등 scope WIDEN + 커스텀 client_name 이 허용됩니다.

Rate limit

/oauth/registerremote IP 기준 분당 10건 으로 제한됩니다. 초과 시:

필드
HTTP status429 Too Many Requests
errorrate_limited
error_descriptiontoo many registration requests
Retry-After 헤더❌ 미설정

Retry-After 가 없으므로 RP 는 exponential backoff 으로 재시도하세요. DCR 은 설치/최초 1회성 등록이 정상 패턴입니다 — 매 요청마다 등록을 반복하지 말고, 발급받은 client_id 를 저장해 재사용하세요(멱등 재등록으로 복구 가능).

에러 코드

모든 에러는 { "error": "...", "error_description": "..." } JSON 으로 반환됩니다.

errorHTTP의미처리
invalid_redirect_uri400redirect_uris 누락 / fragment 포함 / allowlist 불일치URI 를 allowlist 값과 정확히 맞추거나 운영팀에 등록 요청
invalid_client_metadata400검증 실패하거나 지원하지 않는(seed 안 된) scopescope 를 허용 집합으로 제한, 요청 본문 점검
invalid_token401initial access token 게이트가 켜졌는데 토큰이 없거나 틀림Authorization: Bearer 토큰 확인
rate_limited429IP 기준 분당 10건 초과exponential backoff 후 재시도, 등록 결과 캐시
server_error500서버 측 설정 문제(system bot 충돌 등)일시 오류 — 운영팀 문의

보안 모델 (방어 기준)

DCR 은 unauthenticated 라 가장 위험한 surface 입니다. 인증 대신 다음 다층 통제로 보호됩니다.

  • redirect_uri allowlist — 임의 redirect 등록 차단(anti-phishing 핵심). authorize 와 동일 출처 공유.
  • 강제 public 형상client_type=public + token_endpoint_auth_method=none. 유출될 secret 자체가 없음, PKCE 필수.
  • scope 상한 — unauthenticated 는 agent:tools.invoke 도달 불가. baseline 만 보장.
  • 고정 client_name — unauthenticated 경로는 caller 의 client_name 을 신뢰하지 않고 consent 화면 위장을 막는 고정 라벨 사용.
  • system developer ownership — 모든 DCR client 가 단일 system bot 소유 → bulk audit / kill-switch 가 간단.
  • 멱등 dedup + rate limit — 중복 발급·등록 폭주 차단.

레퍼런스

Identity가 제품의 신뢰를 만듭니다.