놀아 Account
Contents

API reference

Request and response specs for every 놀아 Account API, OAuth endpoints included.

These are the four endpoints 놀아 Account provides. Every example is written against this server (https://account.nola.kr).

GET /oauth/authorize

Sends the user to the sign-in and consent screens. This is not a server API but an address you send the browser to.

ParameterRequiredValue
response_typeRequiredFixed to code
client_idRequiredThe value issued in My account
redirect_uriRequiredMust match the registered callback exactly
scopeRequiredSpace-separated. If empty: invalid_scope
stateRequiredA random value against CSRF. If missing: invalid_request
code_challengeRequiredPKCE. If missing: pkce_required
code_challenge_methodRecommendedOnly S256 is allowed. Treated as S256 if omitted
ui_localesOptionalLanguage of the sign-in and consent screens. ko, en, vi. Several allowed, space-separated.
A language the user chose themselves wins. No effect on authentication

On success, the user returns to the callback URL with ?code=...&state=... appended. An authorization code is valid for 10 minutes and single-use.

POST /oauth/token

Send it as application/x-www-form-urlencoded. Always call it from your server — it carries client_secret.

Exchange an authorization code

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"

Refresh a token

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"

Response (same for both)

{
  "access_token": "…",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "…",
  "scope": "profile.avatar profile.basic"
}
A refresh also issues a new refresh_token and revokes the old one (refresh token rotation). Be sure to store the new refresh_token from the response. If you keep using the old one, the next refresh fails.
LifetimeDefault
access_token1 hour (see expires_in)
refresh_token30 days
Authorization code10 minutes · single-use

GET /oauth/userinfo

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"
}

profile_image_url appears only when profile.avatar is granted, and is null when there is no picture. email appears only when the conditions in the Scope reference are met.

sub is different for each service (pairwise). The same person gets a different value in a different service. Use it as the key that identifies a user, but not to match users across services.

GET /oauth/domain-info

Only for the service.domain.read scope. Returns the list of services the user has registered.

curl https://account.nola.kr/oauth/domain-info \
  -H "Authorization: Bearer ACCESS_TOKEN"
{
  "sub": "pws_…",
  "scope": "profile.basic service.domain.read",
  "services": [
    { "name": "…", "description": "…", "domain": "https://…",
      "status": "active", "created_at": "…", "verified_at": "…" }
  ]
}

Without the scope, the response is 403 insufficient_scope.

Disconnecting — there is no public endpoint

Currently, 놀아 Account has no public API for revoking tokens (no revoke endpoint). That means your service has no way to handle “disconnect 놀아 Account” with a call.

So build your service to sign the user out quietly when it receives 401 invalid_token. When the user has cleaned up the connection on the 놀아 Account side, or the token has expired, that is the only signal your service can get.

Signing out of your own service only requires clearing your service's session. There is no need to end the 놀아 Account session too.

Error response format

{ "error": "invalid_grant", "error_description": "pkce verification failed" }

error_description may be absent. The full list is in the Error code dictionary.