OAuth 2.0 연동 가이드
Authorization 요청부터 토큰 교환, UserInfo 조회까지 전체 흐름을 설명하는 연동 가이드입니다.
놀아 계정은 Authorization Code + PKCE 방식의 OAuth 2.0을 지원합니다. 이 문서는 전체 흐름을 처음부터 끝까지 설명합니다. 바로 붙여보고 싶으시면 5분 만에 붙이기가 더 빠릅니다.
전체 흐름
[내 서비스] [놀아 계정] [사용자]
│ │ │
1. verifier/challenge 생성 │ │
│──── 2. /oauth/authorize ──────▶│ │
│ │──── 3. 로그인·동의 ───────▶│
│ │◀─── 4. 동의 ───────────────│
│◀─── 5. code + state 콜백 ──────│ │
6. state 검증 │ │
│──── 7. /oauth/token ──────────▶│ (서버 → 서버) │
│◀─── 8. access/refresh token ───│ │
│──── 9. /oauth/userinfo ───────▶│ │
│◀─── 10. 사용자 정보 ───────────│ │
7번부터는 반드시 서버에서 합니다. client_secret이 들어가기 때문입니다.
엔드포인트
| 역할 | 주소 |
|---|---|
| 인증 요청 | https://account.nola.kr/oauth/authorize |
| 토큰 교환·갱신 | https://account.nola.kr/oauth/token |
| 사용자 정보 | https://account.nola.kr/oauth/userinfo |
| 서비스 도메인 정보 | https://account.nola.kr/oauth/domain-info |
파라미터와 응답 필드는 API 레퍼런스에 표로 정리돼 있습니다.
1. PKCE 값 준비
code_challenge 없이 요청하면
pkce_required로 거부되고, 방식은 S256만 받습니다.// 사용자를 보내기 전에, 서버에서 $verifier = rtrim(strtr(base64_encode(random_bytes(32)), '+/', '-_'), '='); $challenge = rtrim(strtr(base64_encode(hash('sha256', $verifier, true)), '+/', '-_'), '='); $state = bin2hex(random_bytes(16)); $_SESSION['nolaa_verifier'] = $verifier; // 7번에서 씀 $_SESSION['nolaa_state'] = $state; // 6번에서 씀
2. 인증 요청
사용자의 브라우저를 아래 주소로 보냅니다.
https://account.nola.kr/oauth/authorize ?response_type=code &client_id=YOUR_CLIENT_ID &redirect_uri=YOUR_REDIRECT_URI &scope=profile.basic%20profile.avatar &state=RANDOM_STATE &code_challenge=CODE_CHALLENGE &code_challenge_method=S256
client_id·redirect_uri·state·scope·code_challenge가
모두 필수입니다. 하나라도 빠지면 거부됩니다.
redirect_uri는 마이페이지에 등록한 콜백과 문자 하나까지 같아야 합니다.
끝 슬래시, http/https, 포트가 다르면 invalid_redirect_uri입니다.화면 언어 지정 — ui_locales (선택)
이 값을 붙이면 로그인·계정 확인·동의 화면이 그 언어로 나옵니다. 베트남어 서비스에서 넘어온 사용자가 한국어 화면을 마주하지 않게 하는 용도입니다.
&ui_locales=vi
- 지원하는 값은
ko·en·vi입니다. 그 밖의 값은 조용히 무시되고 기본 규칙을 따릅니다. - 공백으로 여러 개를 넣으면 지원하는 첫 번째를 씁니다. 예:
ui_locales=vi en - 사용자가 놀아 계정에서 직접 고른 언어가 있으면 그쪽이 우선합니다. 고른 적이 없는 사용자에게만 적용됩니다 — 사용자의 선택을 서비스가 덮어쓰지 않습니다.
- 생략하면 브라우저 언어(
Accept-Language)로 자동 판별하고, 그래도 모르면 한국어입니다. - 로그인 화면을 거쳐 돌아와도 유지됩니다. 동의가 끝나면 지정은 해제됩니다.
redirect_uri 판단에는 전혀 영향을 주지 않습니다.
사용자는 어느 화면에서든 상단에서 언어를 직접 바꿀 수 있고, 바꿔도 state·code_challenge 같은 값은 그대로 유지됩니다.3. 로그인과 동의
사용자가 로그인돼 있지 않으면 로그인 화면이 먼저 뜹니다. 이미 로그인돼 있어도 계정 확인 화면이 한 번 나와서, 다른 계정으로 바꿀 기회를 줍니다.
그다음 동의 화면에서 요청한 스코프가 사용자에게 그대로 보여집니다.
| 요청한 스코프 | 사용자에게 보이는 문구 |
|---|---|
profile.basic | UUID, 닉네임, 이메일 |
profile.avatar | 프로필 사진 URL |
service.domain.read | 연결된 서비스의 도메인 상세정보 |
한 번 동의한 조합은 기억되어, 다음부터는 동의 화면을 건너뜁니다. 새 스코프를 추가로 요청하면 그때 다시 동의를 받습니다.
4~5. 콜백과 state 검증
동의하면 등록된 콜백 주소로 돌아옵니다.
https://내도메인/oauth/callback?code=abcd1234…&state=RANDOM_STATE
state부터 확인하세요.
보내기만 하고 검사하지 않으면 CSRF 방어가 되지 않습니다.if (!hash_equals($_SESSION['nolaa_state'] ?? '', $_GET['state'] ?? '')) {
// 중단
}
사용자가 거부했거나 요청에 문제가 있으면 ?error=...가 대신 옵니다.
코드별 원인은 에러 코드 사전에 있습니다.
6. 토큰 교환
curl -X POST https://account.nola.kr/oauth/token \ -d "grant_type=authorization_code" \ -d "code=RECEIVED_CODE" \ -d "redirect_uri=YOUR_REDIRECT_URI" \ -d "client_id=YOUR_CLIENT_ID" \ -d "client_secret=YOUR_CLIENT_SECRET" \ -d "code_verifier=SAVED_VERIFIER"
{
"access_token": "…",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "…",
"scope": "profile.avatar profile.basic"
}
인증 코드는 10분 유효 · 1회용입니다. 재시도해도 같은 코드는 두 번 쓸 수 없습니다
(invalid_grant).
토큰 요청의 redirect_uri는 인증 요청 때와 같은 값이어야 합니다.
7. 사용자 정보
curl https://account.nola.kr/oauth/userinfo \ -H "Authorization: Bearer ACCESS_TOKEN"
{
"sub": "pws_xxxxxxxxxxxxxxxx",
"nickname": "놀아유저",
"scope": "profile.avatar profile.basic service.member_email.read",
"profile_image_url": "https://…/uploads/….jpg",
"email": "user@example.com"
}
sub는 서비스마다 다른 값입니다(pairwise).
같은 사람이라도 다른 서비스에서는 다른 sub가 나갑니다. 여러분 서비스 안에서의 사용자 키로 쓰세요.email이 오는 조건은 스코프 레퍼런스를 보세요.
스코프 문제가 아니라 서비스의 이메일 제공 설정일 수 있습니다.
8. 토큰 갱신
access_token은 기본 1시간, refresh_token은 30일입니다.
curl -X POST https://account.nola.kr/oauth/token \ -d "grant_type=refresh_token" \ -d "refresh_token=SAVED_REFRESH_TOKEN" \ -d "client_id=YOUR_CLIENT_ID" \ -d "client_secret=YOUR_CLIENT_SECRET"
9. 연결 해제 · 로그아웃
놀아 계정에는 토큰을 폐기하는 공개 API(revoke 엔드포인트)가 없습니다. 서비스에서 «연결 끊기» 버튼을 눌러 놀아 쪽 토큰까지 무효화하는 호출은 지금 불가능합니다.
그래서 서비스는 401 invalid_token을 받으면 조용히 로그아웃 처리하도록 만들어 두어야 합니다.
사용자가 놀아 계정 쪽에서 정리했거나 토큰이 만료된 상황에서 서비스가 알 수 있는 유일한 신호입니다.
서비스 자체 로그아웃은 여러분 세션만 지우면 됩니다. 놀아 계정 세션까지 끊을 필요는 없습니다.
연동 체크리스트
- 서비스 등록 · 도메인 인증 완료 · 콜백 URL 등록 (셋 다 돼야 상태가 «운영중»이 됩니다)
redirect_uri를 상수로 고정했는가- 요청마다 새
state·code_verifier를 만들고 세션에 저장하는가 - 콜백에서
state를 검사하는가 - 토큰 교환을 서버에서 하는가
- 새
refresh_token을 저장하는가 401을 받았을 때의 처리가 있는가
배포 전에는 보안 체크리스트를 한 번 더 훑어보세요.