PLAYUS 로그인
OAuth 2.0 Authorization Code + PKCE S256과 OpenID Connect를 사용합니다. client_secret이 필요한 서버 기반 클라이언트입니다. 브라우저에서 토큰 교환을 하지 마세요.
엔드포인트#
| 용도 | 주소 |
|---|---|
| Discovery | https://www.playus.app/.well-known/openid-configuration |
| Authorization | https://www.playus.app/oauth/authorize |
| Token | POST https://www.playus.app/v1/oauth/token |
| Userinfo | GET https://www.playus.app/v1/oauth/userinfo |
| JWKS | GET https://www.playus.app/v1/oauth/jwks |
실제 환경의 Discovery 응답을 확인하세요. 이 가이드와 배포된 설정이 다르면 운영 담당자와 확인합니다.
1. 로그인 시작#
import { pkcePair, randomState } from './playus-server.js';
const { verifier, challenge } = pkcePair();
const state = randomState();
const nonce = randomState();
// 게임의 서버 세션에 저장. 요청마다 새로 만들고 짧은 만료 시간을 설정합니다.
req.session.playus = { state, nonce, verifier, createdAt: Date.now() };
res.redirect(playus.authorizeUrl({
redirectUri: CALLBACK_URL,
state, nonce, codeChallenge: challenge,
scope: 'openid profile rewards sessions',
}));
요청은 response_type=code와 code_challenge_method=S256을 사용합니다. scope는 openid, profile, rewards, sessions입니다. 앱에 등록된 범위 내에서 요청하세요.
2. 콜백 검증과 코드 교환#
const pending = req.session.playus;
delete req.session.playus; // 성공/실패와 관계없이 한 번만 사용
if (!pending || Date.now() - pending.createdAt > 5 * 60_000 ||
typeof req.query.state !== 'string' || req.query.state !== pending.state) {
throw new Error('Invalid login state');
}
if (req.query.error) throw new Error('PLAYUS login was cancelled');
if (typeof req.query.code !== 'string') throw new Error('Missing code');
const identity = await playus.exchangeCode(req.query.code, {
redirectUri: CALLBACK_URL,
codeVerifier: pending.verifier,
nonce: pending.nonce,
});
// identity.sub로 게임 계정을 조회/생성하고 게임 자체 세션을 발급합니다.
위 코드는 Express 스타일의 흐름 예시입니다. 세션 미들웨어, Secure·HttpOnly·SameSite 쿠키, 계정 생성·연결과 게임 세션 발급은 게임에서 구현해야 합니다. 기존 로그인 계정에 연결할 때는 소유권을 확인하고, 이미 다른 계정에 연결된 sub를 자동으로 덮어쓰지 마세요.
토큰 교환 요청#
curl --fail-with-body --user "$PLAYUS_CLIENT_ID:$PLAYUS_CLIENT_SECRET" \
-H 'User-Agent: MyGame/1.0' \
--data-urlencode 'grant_type=authorization_code' \
--data-urlencode "code=$PLAYUS_CODE" \
--data-urlencode 'redirect_uri=https://game.example.com/auth/playus/callback' \
--data-urlencode "code_verifier=$PLAYUS_CODE_VERIFIER" \
https://www.playus.app/v1/oauth/token
응답 필드는 access_token, token_type(Bearer), expires_in(3600), scope, id_token입니다. 인가 코드는 120초 유효하며 한 번만 사용할 수 있습니다. refresh_token은 제공하지 않습니다. 게임은 검증된 로그인으로 자기 세션을 관리합니다.
ID Token 검증#
서명 ES256, JWKS의 kid, iss, aud=client_id, exp와 요청한 nonce를 확인합니다. 키트의 exchangeCode가 검증을 수행합니다. JWT 페이로드를 디코딩하는 것만으로 로그인시키지 마세요. sub는 앱별 가명 pu_…입니다. 이메일·전화번호·PLAYUS 내부 회원 번호는 제공하지 않습니다.
연결 해제#
연결이 해제되면 userinfo와 해당 sub의 보상·기록 요청이 거절됩니다. unknown_sub를 받으면 게임의 PLAYUS 연결 상태를 해제하고 재연결을 안내합니다. 재연결 시 같은 앱의 sub가 다시 사용될 수 있습니다.