Skip to content

REST API ​

통합회원 REST API 의 엔드포인트별 요청과 응답을 설명합니다. 예제는 실제 서버 응답입니다. OpenID Connect 라이브러리를 사용하면 대부분의 API 를 직접 호출하지 않습니다.

상태 확정 · 최종 확인 2026-09-30


시작하기 전에 ​

로그인 과정 ​

  1. 연동 서비스가 사용자 브라우저를 인가 코드 요청 URL 로 이동시킵니다.
  2. 사용자가 통합회원 화면에서 로그인하고, 최초 연결 시 제3자 제공 동의를 완료합니다.
  3. 통합회원이 redirect_uri 로 인가 코드를 전달합니다.
  4. 연동 서비스 서버가 인가 코드로 토큰 요청을 수행하고, ID 토큰을 검증합니다.
  5. 연동 서비스가 ID 토큰의 sub 로 회원을 조회하거나 등록하고, 연동 서비스 세션을 발급합니다.

공통 사항 ​

  • 모든 URL 은 호스트를 기준으로 합니다. 호스트는 이해하기 › 도입 안내를 참고하시기 바랍니다.
  • 토큰, 사용자 정보, 토큰 폐기 엔드포인트는 서버 간 호출 전용입니다. CORS 를 허용하지 않으므로 브라우저에서 호출할 수 없습니다.
  • 파라미터 표의 필수 여부는 연동 서비스가 지켜야 하는 기준입니다. 서버가 누락을 거부하는 파라미터는 client_id, redirect_uri, response_type, scope, PKCE 이며, state 와 nonce 는 누락되어도 거부하지 않습니다. 두 값을 보내지 않으면 CSRF 와 재사용 방지가 동작하지 않습니다.
  • 리다이렉트 응답의 상태 코드는 303 입니다.
항목고정값
인가 방식Authorization Code + PKCE(S256)
response_typecode
클라이언트 인증client_secret_post (요청 본문). HTTP Basic 헤더는 지원하지 않습니다
scopeopenid, email, offline_access
회원번호pairwise sub
서명RS256. JWKS 로 공개키를 게시하며 kid 로 키를 선택합니다
시각 허용 오차exp +60초, iat −60초

디스커버리 ​

서버 설정 정보를 JSON 으로 제공합니다. 라이브러리는 이 주소로 엔드포인트와 서명키 위치를 조회합니다.

메서드URL인증 방식
GET/.well-known/openid-configuration없음

응답

json
{
  "issuer": "https://membership.m-box.com",
  "authorization_endpoint": "https://membership.m-box.com/oauth/authorize",
  "token_endpoint": "https://membership.m-box.com/oauth/token",
  "userinfo_endpoint": "https://membership.m-box.com/oauth/userinfo",
  "jwks_uri": "https://membership.m-box.com/oauth/jwks",
  "end_session_endpoint": "https://membership.m-box.com/oauth/logout",
  "revocation_endpoint": "https://membership.m-box.com/oauth/revoke",
  "scopes_supported": ["openid", "email", "offline_access"],
  "claims_supported": ["sub", "email", "email_verified", "sid", "auth_time", "iss"],
  "claim_types_supported": ["normal"],
  "response_types_supported": ["code"],
  "response_modes_supported": ["form_post", "fragment", "query"],
  "grant_types_supported": ["authorization_code", "refresh_token"],
  "subject_types_supported": ["pairwise"],
  "code_challenge_methods_supported": ["S256"],
  "token_endpoint_auth_methods_supported": ["client_secret_post"],
  "id_token_signing_alg_values_supported": ["RS256"],
  "authorization_response_iss_parameter_supported": true,
  "claims_parameter_supported": false,
  "request_parameter_supported": false,
  "request_uri_parameter_supported": false
}

NOTE

디스커버리 항목 참고

  • PAR(pushed_authorization_request_endpoint)은 지원하지 않으며 디스커버리에 포함되지 않습니다.
  • token_endpoint_auth_methods_supported 는 client_secret_post 뿐입니다. HTTP Basic 헤더(client_secret_basic)로 요청하면 401 invalid_client 가 반환됩니다.
  • response_mode 는 지정하지 않으며 기본값(query)만 사용합니다.
  • sid 는 백채널 로그아웃을 제공하지 않으므로 사용하지 않습니다. aud, exp, iat, nonce, at_hash 는 목록에 없으나 ID 토큰에 항상 포함됩니다.

JWKS ​

ID 토큰 서명 검증용 공개키 목록입니다. 키는 kid 로 구분합니다. 캐시하여 사용하되, 토큰 헤더의 kid 가 목록에 없으면 다시 조회해야 합니다(키 교체).

메서드URL인증 방식
GET/oauth/jwks없음

응답

json
{ "keys": [ { "kty": "RSA", "kid": "k-2026-09-23-db08ab", "alg": "RS256", "use": "sig", "n": "…", "e": "AQAB" } ] }

인가 코드 요청 ​

사용자에게 로그인 화면(최초 연결 시 동의 화면 포함)을 표시하고, 완료되면 redirect_uri 로 인가 코드를 전달합니다. 사용자 브라우저를 이 URL 로 이동시키며, 전체 페이지 이동으로 호출해야 합니다(iframe 차단).

메서드URL인증 방식요구 사항
GET/oauth/authorize없음클라이언트 등록, redirect_uri 등록

요청 — 쿼리 파라미터

이름타입설명필수
client_idString발급받은 클라이언트 IDO
redirect_uriString등록한 값과 정확히 일치하는 주소. URL 인코딩O
response_typeStringcode 고정O
scopeString공백으로 구분하며 openid 는 필수입니다. 예: openid email. 지원하지 않는 scope 는 오류 없이 무시됩니다O
stateStringCSRF 방지용 임의값(32자 이상 권장). 콜백에 그대로 전달됩니다O
nonceStringID 토큰 재사용 방지용 임의값. ID 토큰의 nonce 로 전달됩니다O
code_challengeStringBASE64URL(SHA256(code_verifier)). code_verifier 는 43~128자 임의 문자열이며 세션에 보관합니다O
code_challenge_methodStringS256 고정O
promptStringlogin: 통합회원 세션이 있어도 재인증 · consent: 동의 화면 표시(offline_access 요청 시 필수, 이미 동의한 사용자에게도 매번 표시) · create: login_hint 가 있으면 기존 회원 전환 화면(활용하기 › 기존 회원 연결), 없으면 가입 화면. 통합회원 세션이 있으면 계정 확인 화면을 먼저 표시 · none: 화면 없이 처리(세션이 없으면 login_required, 동의가 필요하면 consent_required). 권장하지 않으며, 다른 값과 함께 사용하면 invalid_requestX
login_hintString로그인 · 가입 화면의 이메일 입력란에 미리 채울 값X
max_ageInteger마지막 인증 후 허용 시간(초). 초과 시 재인증하며, ID 토큰에 auth_time 이 포함됩니다X

응답 — redirect_uri 쿼리 파라미터

이름타입설명필수
codeString인가 코드. 60초 안에 한 번 교환할 수 있습니다. 교환에 실패한 경우(잘못된 code_verifier 등) 코드가 소모되지 않으므로 60초 안에 다시 요청할 수 있습니다성공 시 O
stateString요청 시 전달한 값. 일치하지 않으면 처리를 중단해야 합니다O
issString발급자. 디스커버리의 issuer 와 비교합니다(RFC 9207)O
errorString오류 코드. 문제 해결 › 오류 코드실패 시 O
error_descriptionString개발자용 설명. 서버 기술 오류는 영문, 사용자 행위(취소 등)는 한글입니다. 문구는 변경될 수 있으므로 분기에는 error 를 사용해야 합니다실패 시 O

response_type 오류는 쿼리가 아닌 fragment(#error=unsupported_response_type…)로 전달됩니다. redirect_uri 나 client_id 가 잘못되어 리다이렉트할 수 없는 오류는 통합회원 오류 화면에 표시됩니다.

예제

GET /oauth/authorize
  ?client_id=remit-web
  &redirect_uri=https%3A%2F%2Fwww.remit.example%2Fcb
  &response_type=code
  &scope=openid%20email
  &state=Sau634G8avjmwmDjVcNRAKQO5dQ3UTKR
  &nonce=7hAWqHGxvf7iTYF8GLA-Ue5PTHFnLao0
  &code_challenge=tXEQEahZ3p-BDun7VtJuzJ9K7kcvpUMhjhilB-azuio
  &code_challenge_method=S256
성공: https://www.remit.example/cb?code=vgmyQYwAVSz4hZc7lleeZ9ecfNI2iI_Ha-JKpO2ZzzQ&state=Sau634G8…&iss=https%3A%2F%2Fmembership.m-box.com
취소: https://www.remit.example/cb?error=access_denied&error_description=%EC%82%AC%EC%9A%A9%EC%9E%90%EA%B0%80+%EC%B7%A8%EC%86%8C%ED%96%88%EC%8A%B5%EB%8B%88%EB%8B%A4&state=Sau634G8…&iss=…   (「사용자가 취소했습니다」)
PKCE 누락: https://www.remit.example/cb?error=invalid_request&error_description=Authorization+Server+policy+requires+PKCE+to+be+used+for+this+request&state=…&iss=…

토큰 요청 ​

인가 코드로 ID 토큰과 액세스 토큰을 발급받습니다. 시크릿이 필요하므로 연동 서비스 서버에서 호출해야 합니다.

메서드URL인증 방식요구 사항
POST/oauth/tokenclient_secret_post — 요청 본문에 client_id · client_secret 포함. HTTP Basic 헤더는 지원하지 않습니다(401 invalid_client)인가 코드

요청 — 헤더

이름값필수
Content-Typeapplication/x-www-form-urlencodedO

요청 — 본문

이름타입설명필수
grant_typeStringauthorization_code 고정O
codeString인가 코드O
redirect_uriString인가 요청에 사용한 값O
client_idString클라이언트 IDO
client_secretString클라이언트 시크릿O
code_verifierStringcode_challenge 생성에 사용한 원본 값O

응답 — 본문

이름타입설명필수
id_tokenString사용자 정보가 담긴 JWT. 검증 후 사용해야 합니다O
access_tokenString사용자 정보 조회용O
token_typeStringBearerO
expires_inInteger액세스 토큰 유효 시간(초). 600O
scopeString실제로 부여된 scope. 무시된 항목은 포함되지 않습니다O
refresh_tokenStringoffline_access 와 prompt=consent 를 함께 요청한 경우에만 발급X

ID 토큰 페이로드

클레임설명항상 제공 여부
iss발급자. 디스커버리의 issuer 와 일치해야 합니다예
aud연동 서비스의 client_id 와 일치해야 합니다예
sub서비스별 회원번호예
email email_verifiedemail scope 요청 시 포함아니오
nonce인가 요청의 nonce 와 일치해야 합니다예
iat exp발급 · 만료 시각(Unix 초). exp 가 지났으면 거부해야 합니다예
at_hash함께 발급된 액세스 토큰의 해시. 라이브러리가 검증합니다예
auth_time실제 인증 시각. prompt=login 또는 max_age 요청 시에만 포함아니오

검증 순서는 헤더의 kid 로 JWKS 에서 키 선택, RS256 서명 확인, iss · aud · exp · nonce 확인입니다. 라이브러리의 ID 토큰 검증 기능이 이를 모두 수행합니다. aud 는 단일 문자열이며 azp 는 없습니다. 시각 허용 오차는 exp 현재 시각 +60초, iat 현재 시각 −60초입니다. 직접 구현하는 절차는 활용하기 › ID 토큰 검증을 참고하시기 바랍니다.

예제

bash
curl -X POST "https://membership.m-box.com/oauth/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=authorization_code" \
  -d "code=vgmyQYwAVSz4hZc7lleeZ9ecfNI2iI_Ha-JKpO2ZzzQ" \
  -d "redirect_uri=https://www.remit.example/cb" \
  -d "client_id=remit-web" \
  -d "client_secret=${CLIENT_SECRET}" \
  -d "code_verifier=${CODE_VERIFIER}"
json
{
  "access_token": "fHh6IXkn_hauA14JsYGzs4eQmS0y3lnwe9wfMhxQZzL",
  "expires_in": 600,
  "id_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImstMjAyNi0wOS0yMy1kYjA4YWIifQ.eyJzdWIiOi…",
  "scope": "openid email",
  "token_type": "Bearer"
}

ID 토큰 헤더 · 페이로드(디코드):

json
{ "alg": "RS256", "typ": "JWT", "kid": "k-2026-09-23-db08ab" }
json
{
  "sub": "rm_7996cf354b131e55b31f262540e4c50f",
  "email": "hong@example.com",
  "email_verified": true,
  "nonce": "7hAWqHGxvf7iTYF8GLA-Ue5PTHFnLao0",
  "at_hash": "LxK3KvwgAKqAHoh0a5a0sg",
  "aud": "remit-web",
  "exp": 1790149873,
  "iat": 1790149273,
  "iss": "https://membership.m-box.com"
}

오류 — HTTP 400/401, 본문 {"error": "…", "error_description": "…"}

HTTPerrorerror_description원인
400invalid_grantgrant request is invalid코드 만료(60초) · 코드 재사용 · code_verifier 불일치 · redirect_uri 불일치
401invalid_clientclient authentication failedclient_id · client_secret 오류
401invalid_clientclient_secret_basic 은 지원하지 않는다. client_id 와 client_secret 을 요청 본문에 넣어(client_secret_post) 보낼 것.Authorization: Basic 헤더로 요청한 경우. 요청 본문 방식(client_secret_post)만 지원합니다. 인가 코드는 소모되지 않으므로 방식을 수정하여 같은 코드로 다시 요청할 수 있습니다
400invalid_request(누락 항목 설명)필수 파라미터 누락

토큰 폐기 엔드포인트(/oauth/revoke)도 Basic 헤더로 요청하면 401 invalid_client 를 반환합니다.

토큰 갱신 ​

리프레시 토큰으로 새 액세스 토큰과 ID 토큰을 발급받습니다. 리프레시 토큰도 새 값으로 교체되며 기존 값은 즉시 무효가 되므로, 응답의 새 값을 저장해야 합니다.

메서드URL인증 방식요구 사항
POST/oauth/tokenclient_secret_postoffline_access scope 로 발급된 리프레시 토큰

요청 — 본문

이름타입설명필수
grant_typeStringrefresh_token 고정O
refresh_tokenString현재 리프레시 토큰O
client_idString클라이언트 IDO
client_secretString클라이언트 시크릿O

응답 — 본문: 토큰 요청과 같은 구조(access_token, expires_in, id_token, refresh_token, scope, token_type)이며, refresh_token 에 새 값이 전달됩니다.

갱신 응답의 id_token 에는 최초 인가 요청의 nonce 가 포함됩니다. 갱신 시에는 nonce 를 검증하지 않으며(표준), 서명 · iss · aud · exp 와 sub 가 최초와 같은지 확인합니다.

오류

HTTPerror원인조치
400invalid_grant (grant request is invalid)토큰 만료(30일), 이미 교체된 토큰, 계정 정지 · 탈퇴, 사용자의 연결 해제(동의 철회)재시도하지 않고 토큰을 폐기한 뒤 재로그인을 안내합니다

사용자 정보 조회 ​

액세스 토큰으로 사용자 정보를 조회합니다. ID 토큰에 같은 정보가 포함되어 있으므로 일반적으로 호출할 필요가 없습니다.

메서드URL인증 방식
GET/oauth/userinfo액세스 토큰 (Bearer)

요청 — 헤더

이름값필수
AuthorizationBearer ${ACCESS_TOKEN}O

응답 — 본문

이름타입설명필수
subString서비스별 회원번호O
emailString이메일email scope 요청 시
email_verifiedBoolean이메일 확인 여부email scope 요청 시

예제

bash
curl "https://membership.m-box.com/oauth/userinfo" -H "Authorization: Bearer ${ACCESS_TOKEN}"
json
{ "sub": "rm_7996cf354b131e55b31f262540e4c50f", "email": "hong@example.com", "email_verified": true }

오류

HTTPerror원인
400invalid_request — no access token provided (+ WWW-Authenticate: Bearer realm="…")Authorization 헤더 누락
401invalid_token — invalid token provided만료 · 폐기된 액세스 토큰

토큰 폐기 ​

액세스 토큰 또는 리프레시 토큰을 즉시 무효화합니다. 통합회원 로그아웃(/oauth/logout)을 요청하면 해당 서비스의 토큰은 통합회원이 함께 폐기하므로, 이 엔드포인트는 연동 서비스만 로그아웃할 때 사용합니다.

메서드URL인증 방식
POST/oauth/revokeclient_secret_post

요청 — 본문

이름타입설명필수
tokenString폐기할 토큰O
token_type_hintStringaccess_token 또는 refresh_tokenX
client_id client_secretString클라이언트 인증O

응답: 200, 본문 없음. 이미 무효인 토큰도 200 을 반환합니다. 폐기된 액세스 토큰으로 사용자 정보를 조회하면 401 invalid_token 이 반환됩니다.

로그아웃 ​

통합회원 세션을 종료합니다. 사용자 브라우저를 이 URL 로 이동시키면 확인 화면이 표시되며, 사용자가 로그아웃을 선택하면 세션이 종료됩니다.

메서드URL인증 방식
GET/oauth/logout없음 (브라우저 세션)

요청 — 쿼리 파라미터

이름타입설명필수
id_token_hintString로그인 시 발급받은 ID 토큰. 요청한 클라이언트를 식별합니다권장
client_idStringid_token_hint 를 보내지 않는 경우 클라이언트 식별용. 둘 중 하나는 전달해야 합니다X
post_logout_redirect_uriString로그아웃 후 이동할 주소. 등록된 값만 허용됩니다(설정하기 › 로그아웃 리다이렉트 URI)X
stateString복귀 주소로 그대로 전달됩니다X

확인 화면 — 제목은 "MBOX 통합회원에서 로그아웃할까요?"이며, 본문에 요청한 서비스 이름과 로그아웃 · 로그인 유지 버튼이 표시됩니다. id_token_hint 와 client_id 가 모두 없으면 서비스 이름 대신 "이용 중인 서비스"가 표시됩니다.

결과

상황결과
로그아웃 + 등록된 post_logout_redirect_uri통합회원 세션이 종료되고 해당 주소로 303 리다이렉트됩니다. state 를 전달한 경우 ?state=… 로 함께 전달됩니다
로그아웃 + 복귀 주소 없음통합회원 세션이 종료되고 완료 화면("로그아웃되었습니다")이 표시됩니다
로그인 유지통합회원 세션이 유지됩니다. 복귀 주소를 전달한 경우 로그아웃과 같은 방식으로 state 와 함께 303 리다이렉트됩니다. 이후 인가 요청은 화면 없이 처리되며, 요청한 서비스의 토큰은 로그아웃과 마찬가지로 폐기됩니다
등록되지 않은 post_logout_redirect_uri연동 서비스로 이동하지 않고, 400 과 함께 통합회원 오류 화면(invalid_request: post_logout_redirect_uri not registered)이 표시됩니다

WARNING

복귀 여부로 로그아웃을 판단할 수 없습니다

로그아웃과 로그인 유지의 복귀 응답은 상태 코드, 복귀 주소, state 값이 모두 같으며, 결과를 구분하는 파라미터가 없습니다. 따라서 연동 서비스 세션은 사용자를 /oauth/logout 으로 이동시키기 전에 삭제해야 합니다.

로그아웃을 요청한 서비스의 액세스 · 리프레시 토큰은 두 경우 모두 통합회원이 폐기합니다(offline_access 로 발급된 토큰 포함). 복귀 후 해당 토큰으로 갱신하면 invalid_grant, 사용자 정보 조회는 invalid_token 이 반환됩니다. 다른 서비스의 토큰에는 영향이 없습니다.

이 API 는 통합회원 세션만 종료합니다. 각 서비스의 세션은 각 서비스가 종료해야 합니다(백채널 로그아웃 미제공).