개요
놀아:회원은 자체 회원가입과 외부 서비스용 OAuth 로그인을 함께 제공하는 서버입니다.
외부 서비스는 서비스별 고유 식별자/닉네임/이메일 주소를 기본 제공받으며, 프로필 사진 URL은 요청 시 제공받습니다.
(이메일은 사용자 동의를 거쳐 제공되며, 관리자가 이메일 제공을 중지한 서비스는 제외됩니다.)
- 외부 서비스는 사전 도메인 인증이 필요합니다.
- 첫 로그인에는 사용자 동의가 필요합니다.
state와 PKCE(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_method는 S256만 허용됩니다.
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일 수 있습니다.
3. 동의 화면
사용자가 해당 서비스에 처음 로그인하면 동의 화면을 보여줍니다.
화면에는 서비스 이름, 서비스 설명, 요청 scope, 전달되는 정보가 표시됩니다.
- 전달 정보: 닉네임, 이메일 주소, 프로필 사진 URL(요청 시)
- 전달하지 않는 정보: 비밀번호
- 이메일은 기본 제공되며, 관리자가 이메일 제공을 중지한 서비스는 제외됩니다.
- 사용자는 동의 또는 거부를 선택할 수 있습니다.
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차단됨