놀아 놀아:회원

OAuth 2.0 · Developer Guide

놀아:회원 OAuth 2.0 가이드

이 문서는 놀아:회원 OAuth 2.0 제공 서버를 외부 서비스 개발자가 연동할 때 필요한 규격, 요청 흐름, 응답 형식, 보안 조건을 설명합니다. 사용자 정보는 고유 식별자·닉네임·이메일 주소를 기본 제공하며, 프로필 사진 URL은 요청 시 제공합니다.

개요

놀아:회원은 자체 회원가입과 외부 서비스용 OAuth 로그인을 함께 제공하는 서버입니다. 외부 서비스는 서비스별 고유 식별자/닉네임/이메일 주소를 기본 제공받으며, 프로필 사진 URL은 요청 시 제공받습니다. (이메일은 사용자 동의를 거쳐 제공되며, 관리자가 이메일 제공을 중지한 서비스는 제외됩니다.)

  • 외부 서비스는 사전 도메인 인증이 필요합니다.
  • 첫 로그인에는 사용자 동의가 필요합니다.
  • statePKCE(S256)를 사용합니다.
  • authorization code는 1회용이며 10분 유효합니다.
  • sub는 서비스별로 달라지는 고유 식별자입니다.

엔드포인트

GET /oauth/authorize Authorization 요청 진입점
POST /oauth/consent 동의/거부 처리
POST /oauth/token authorization code / refresh token 교환
GET /oauth/userinfo 사용자 프로필 조회

1. Authorization 요청

외부 서비스는 사용자를 다음 형태의 URL로 이동시켜야 합니다.

GET https://account.nola.kr/oauth/authorize
  ?response_type=code
  &client_id=CLIENT_ID
  &redirect_uri=https://service.example.com/oauth/callback
  &scope=profile.basic profile.avatar
  &state=RANDOM_STATE
  &code_challenge=BASE64URL_SHA256_CODE_VERIFIER
  &code_challenge_method=S256
필수 조건
  • response_type는 반드시 code여야 합니다.
  • redirect_uri는 등록된 callback URL과 정확히 일치해야 합니다.
  • 서버는 등록된 callback URL을 기준으로 처리합니다. 요청값이 다르면 invalid_redirect_uri로 실패합니다.
  • scope는 공백으로 구분합니다. 콤마는 표준 구분자가 아닙니다.
  • state는 CSRF 방지와 응답 매칭을 위해 매 요청마다 랜덤해야 합니다.
  • code_challenge_methodS256만 허용됩니다.

2. 샘플 요청/응답

외부 서비스 개발자가 바로 붙일 수 있도록, 성공/실패 예시를 함께 제공합니다.

Authorization 요청 예시

GET https://account.nola.kr/oauth/authorize?response_type=code&client_id=CLIENT_ID&redirect_uri=https%3A%2F%2Fservice.example.com%2Foauth%2Fcallback&scope=profile.basic%20profile.avatar&state=RANDOM_STATE&code_challenge=BASE64URL_SHA256_CODE_VERIFIER&code_challenge_method=S256

Authorization 성공 후 callback 예시

GET https://service.example.com/oauth/callback?code=AUTHORIZATION_CODE&state=RANDOM_STATE

redirect_uri 불일치 실패 예시

GET https://service.example.com/oauth/callback?error=invalid_redirect_uri&error_description=redirect_uri%20does%20not%20match%20registered%20callback%20URL&state=RANDOM_STATE

Token 요청 예시

POST https://account.nola.kr/oauth/token
grant_type=authorization_code
client_id=CLIENT_ID
client_secret=CLIENT_SECRET
code=AUTHORIZATION_CODE
redirect_uri=https://service.example.com/oauth/callback
code_verifier=ORIGINAL_CODE_VERIFIER

Token 응답 예시

{
  "access_token": "....",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "....",
  "scope": "profile.basic profile.avatar"
}

UserInfo 요청/응답 예시

GET https://account.nola.kr/oauth/userinfo
Authorization: Bearer ACCESS_TOKEN

{
  "sub": "pws_2G6O...서비스별고유값...",
  "nickname": "nola",
  "profile_image_url": "https://example.com/account/public/uploads/profile/nola.jpg",
  "scope": "profile.basic profile.avatar"
}

실제 응답의 profile_image_url은 등록된 프로필 이미지가 없으면 null일 수 있습니다.

4. Token 교환

동의 후 반환된 code는 1회만 사용할 수 있습니다. 외부 서비스 서버는 백엔드에서 토큰 엔드포인트를 호출합니다.

토큰 요청의 redirect_uri도 반드시 등록된 callback URL과 같아야 합니다. 다르면 invalid_redirect_uri로 실패합니다.

POST https://account.nola.kr/oauth/token
grant_type=authorization_code
client_id=CLIENT_ID
client_secret=CLIENT_SECRET
code=AUTHORIZATION_CODE
redirect_uri=https://service.example.com/oauth/callback
code_verifier=ORIGINAL_CODE_VERIFIER
응답 예시
{
  "access_token": "....",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "....",
  "scope": "profile.basic profile.avatar"
}

5. UserInfo

access token으로 사용자 정보를 조회합니다.

GET https://account.nola.kr/oauth/userinfo
Authorization: Bearer ACCESS_TOKEN
응답 필드
  • sub - 서비스별 고유 식별자
  • nickname - 닉네임
  • email - 이메일 주소(profile.basic이면 기본 포함, 서비스 opt-out/미동의 시 제외)
  • profile_image_url - profile.avatar scope가 있으면 포함
  • scope - 승인된 scope 문자열

Scope

profile.basic

서비스별 고유 식별자, 닉네임, 이메일 주소를 제공합니다. (이메일은 기본 제공, 서비스 opt-out 시 제외)

profile.avatar

서비스별 고유 식별자, 닉네임, 프로필 사진 URL을 제공합니다.

scope는 필요한 최소 범위만 요청해야 하며, 사용자가 동의하지 않은 범위는 발급되지 않습니다.

PKCE

놀아:회원은 PKCE(S256)를 필수로 요구합니다.

  • code_verifier는 외부 서비스가 생성합니다.
  • code_challenge = base64url(SHA256(code_verifier))
  • 토큰 요청 시 원본 code_verifier를 다시 보내 검증합니다.

상태값

draft초안
queued검증 대기
pending_callback콜백 대기
active사용 가능
revoked차단됨

연동 체크리스트

1) 서비스 등록 완료 → 2) 도메인 인증 완료 → 3) callback URL 등록 → 4) client_id / client_secret 확보 → 5) authorize 요청 → 6) consent 처리 → 7) token 교환 → 8) userinfo 호출