728x90

Roblox Open Cloud에서 OAuth 2.0(및 PKCE)을 “실제로 쓰기 위한” 가이드입니다. 문서 기준으로 Roblox는 Open Cloud API 접근을 위해 OAuth 2.0을 제공하고, Authorization Code Flow를 기본으로 하며 PKCE도 지원합니다. 또한 13+ 계정만 앱을 승인(Authorize) 가능하고, OAuth 2.0 앱 등록/게시에는 ID 검증이 필요합니다.
Roblox OAuth2를 쓰는 이유와 큰 그림
왜 필요한가
- API Key 방식은 “내가 내 리소스에 접근”하기엔 편하지만, 제3자(또는 다른 사용자/그룹)의 리소스에 접근하게 하려면 권한 위임(Delegation) 이 필요합니다.
- OAuth2는 사용자의 비밀번호/쿠키를 공유하지 않고, 사용자가 동의한 권한(scope + 리소스 범위) 내에서만 앱이 접근하도록 합니다.
Roblox Open Cloud OAuth2의 핵심 구성요소(역할)
- Resource Owner: Roblox 사용자(또는 그룹 오너)
- Client(App): 당신의 웹/앱/봇/툴
- Authorization Server: Roblox OAuth 서버(동의/토큰 발급)
- Resource Server: Open Cloud API(경험(Experience), 그룹 등 보호 리소스)
지원 플로우 선택: Confidential vs Public + PKCE
Roblox는 Authorization Code Flow를 지원하며, 클라이언트가 secret을 안전하게 보관 가능한지 여부에 따라 구현이 갈립니다.
A. Confidential Client (서버 보유: 웹백엔드/프라이빗 서버)
- 서버가 client_secret을 안전하게 저장 가능
- 권장: Auth Code Flow (서버에서 code → token 교환)
B. Public Client (모바일/브라우저 SPA/데스크톱 앱 등)
- secret을 안전하게 숨길 수 없음
- 권장: Auth Code Flow + PKCE
- PKCE는 code 탈취/리플레이 위험을 크게 줄입니다.
사전 준비: OAuth 2.0 앱 등록(Registration)
앱 등록을 하면 client_id / client_secret이 발급되고, 이를 통해 사용자의 동의를 받아 리소스 접근 권한을 얻습니다.
등록 시 체크포인트
- Redirect URI(콜백 URL): 정확히 등록(스킴/도메인/경로/포트까지)
- 최소 권한(scope 최소화): 필요한 scope만 요청
- 운영/개발 환경 분리: redirect_uri, client_id 분리 권장
- 비밀정보 보관: client_secret은 Vault/Secret Manager 등 사용(코드/이미지에 하드코딩 금지)
엔드포인트/기본 스펙
Roblox OAuth 베이스 URL은 다음으로 안내됩니다.
- Base:
https://apis.roblox.com/oauth - 주요 엔드포인트
GET /v1/authorizePOST /v1/tokenPOST /v1/token/introspectPOST /v1/token/resourcesPOST /v1/token/revokeGET /v1/userinfoGET /.well-known/openid-configuration
300x250
또한 scope 관련 안내로,
openidscope를 요청하면 ID Token(OIDC) 성격을 포함할 수 있고,openid profile로 더 많은 사용자 정보를 얻는 흐름이 언급됩니다.
전체 흐름(Authorization Code + PKCE 기준)
클라이언트가 “인가 요청(Authorize)” URL로 사용자를 보냄
필수 파라미터 핵심
client_idredirect_uriscope(공백으로 구분)response_type=codestate(CSRF 방지)- PKCE 사용 시
code_challengecode_challenge_method=S256
예시: authorize URL(개념 예시)
GET https://apis.roblox.com/oauth/v1/authorize?
client_id=YOUR_CLIENT_ID
&redirect_uri=https%3A%2F%2Fapp.example.com%2Foauth%2Froblox%2Fcallback
&response_type=code
&scope=openid%20profile
&state=RANDOM_CSRF_TOKEN
&code_challenge=BASE64URL_SHA256(verifier)
&code_challenge_method=S256
사용자가 Roblox에서 로그인 + 동의
- 사용자는 어떤 리소스/권한을 줄지 선택하고, Roblox가 인증/동의를 처리합니다.
Roblox가 redirect_uri로 code를 전달
콜백으로 보통 이런 형태로 돌아옵니다.
https://app.example.com/oauth/roblox/callback?code=AUTH_CODE&state=RANDOM_CSRF_TOKEN
서버(또는 앱)가 POST /v1/token으로 code → token 교환
- 결과로 access_token, refresh_token이 나오는 구조가 안내됩니다.
예시(cURL, PKCE 포함)
curl -sS -X POST "https://apis.roblox.com/oauth/v1/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code" \
-d "client_id=YOUR_CLIENT_ID" \
-d "redirect_uri=https://app.example.com/oauth/roblox/callback" \
-d "code=AUTH_CODE_FROM_CALLBACK" \
-d "code_verifier=YOUR_RANDOM_VERIFIER"
Confidential client(서버가 secret 보관 가능)라면, PKCE 대신/또는 추가로 client_secret을 안전한 방식으로 포함하는 패턴을 사용합니다. (정확한 파라미터는 Roblox 구현 가이드/레퍼런스 흐름에 맞추세요)
access_token으로 Open Cloud API 호출
- 이후 Open Cloud API 요청 시
Authorization: Bearer <access_token>형태로 호출하는 패턴이 일반적입니다. (각 Open Cloud API 레퍼런스의 auth 요구사항에 따름)
토큰 운영(필수)
- 만료 시
refresh_token으로 재발급(Refresh Token Grant) - 로그인 해지/권한 철회 시
POST /v1/token/revoke - 서버 측 검증/상태 확인 필요 시
POST /v1/token/introspect - 사용자가 동의한 “접근 가능한 리소스 목록/범위” 확인에
POST /v1/token/resources - 사용자 정보 조회에
GET /v1/userinfo
구현 예시: Node.js(Express) “로그인 버튼 → 콜백 → 토큰 교환”
아래는 “전형적인 구조” 예시입니다. 실제 파라미터는 Roblox 레퍼런스에 맞춰 조정하세요.
로그인 시작 라우트
import express from "express";
import crypto from "crypto";
const app = express();
const CLIENT_ID = process.env.RBX_CLIENT_ID;
const REDIRECT_URI = "https://app.example.com/oauth/roblox/callback";
const AUTH_URL = "https://apis.roblox.com/oauth/v1/authorize";
function base64url(buf) {
return buf.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
}
function sha256(input) {
return crypto.createHash("sha256").update(input).digest();
}
app.get("/auth/roblox", (req, res) => {
// 1) state(=CSRF) 생성 및 세션/스토리지에 보관
const state = base64url(crypto.randomBytes(24));
// 2) PKCE verifier/challenge 생성 및 verifier 보관
const verifier = base64url(crypto.randomBytes(32));
const challenge = base64url(sha256(verifier));
// TODO: state/verifier를 세션(서버) 또는 안전한 저장소에 저장
// 예: req.session.oauth_state = state; req.session.pkce_verifier = verifier;
const scope = encodeURIComponent("openid profile");
const redirect = encodeURIComponent(REDIRECT_URI);
const url =
`${AUTH_URL}?client_id=${CLIENT_ID}` +
`&redirect_uri=${redirect}` +
`&response_type=code` +
`&scope=${scope}` +
`&state=${state}` +
`&code_challenge=${challenge}` +
`&code_challenge_method=S256`;
res.redirect(url);
});
콜백 라우트: code 검증 후 token 교환
app.get("/oauth/roblox/callback", async (req, res) => {
const { code, state } = req.query;
// 1) state 검증(필수: CSRF 방지)
// if (state !== req.session.oauth_state) return res.status(400).send("Invalid state");
// 2) code_verifier 로드
// const verifier = req.session.pkce_verifier;
// 3) 토큰 교환
const tokenUrl = "https://apis.roblox.com/oauth/v1/token";
const body = new URLSearchParams({
grant_type: "authorization_code",
client_id: process.env.RBX_CLIENT_ID,
redirect_uri: "https://app.example.com/oauth/roblox/callback",
code: String(code),
code_verifier: "YOUR_VERIFIER_FROM_SESSION"
});
const r = await fetch(tokenUrl, {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body
});
const token = await r.json();
// token.access_token, token.refresh_token 등을 안전 저장(서버 DB/암호화 저장)
res.json(token);
});
보안 관점 체크리스트
Roblox OAuth2는 “권한 위임”이 핵심이라, 구현 실수 = 계정/리소스 탈취로 이어질 수 있습니다. 아래 항목은 내부 보안점검 기준으로 강력 추천합니다.
Redirect URI 보안
- Redirect URI는 사전 등록된 값과 정확히 매칭되도록 운영
- 와일드카드/동적 리다이렉트 금지(오픈 리다이렉트는 code 탈취로 직결)
- 콜백 엔드포인트에 추가 리다이렉트 파라미터(continue, next 등) 가 있다면 화이트리스트 처리
state는 “필수”
state는 무조건 사용(세션/스토리지에 저장 후 콜백에서 대조)- 목적: CSRF + 로그인 세션 혼동 공격 방지
Public Client는 PKCE 강제
- 모바일/SPA는 secret 보관 불가 → PKCE(S256) 필수
- code_verifier는 요청마다 새로 생성(재사용 금지)
토큰 저장/수명 관리
- access_token: 짧게, 메모리/보호 저장소(서버) 우선
- refresh_token: 가장 민감 → DB 저장 시 암호화(키는 KMS/Vault), 접근 로깅
- 토큰이 브라우저로 내려가야 한다면(가능하면 지양): XSS 방어(HTTPOnly cookie 등) 설계
권한 최소화(Scopes & Resource Boundaries)
- “일단 크게 요청” 금지 → 필요한 scope만
POST /v1/token/resources같은 기능으로 실제 허용 리소스 범위를 서버가 확인하고, 내부 권한 모델에 매핑
철회/로그아웃 처리
- 사용자 로그아웃/연동 해제 시
POST /v1/token/revoke호출 - “연동 해제” UX(설정 페이지)를 제공해서 사용자 통제권 보장
토큰 검증(Introspection) & 이상징후 탐지
- 서버가 토큰을 받아 처리하는 구조라면, 필요 시
POST /v1/token/introspect로 상태 확인 - 로깅 포인트
- authorize 시도/성공/실패
- token 발급/갱신/철회
- scope/리소스 범위 변경
- 비정상 리다이렉트/반복 실패/의심 IP
활용 사례(자주 쓰는 패턴)
Roblox로 로그인(Sign-in with Roblox) + 사용자 프로필 확인
scope=openid profile로 시작- 토큰 교환 후
GET /v1/userinfo로 사용자 식별/기본정보를 얻어 내부 계정과 연동
그룹/경험(Experience) 운영 자동화 툴
- 사용자가 자신/그룹의 경험에 대한 특정 권한만 동의
- 서버는 토큰을 받아 Open Cloud API로 배포/메시지 브로드캐스트/운영 작업 수행
- Roblox는 Node 샘플 앱도 제공하며, 해당 샘플은 PKCE 없는 Auth Code Flow라서 confidential client(서버형) 에만 적합하다고 안내합니다.
최소 테스트 시나리오
- 등록한 Redirect URI로
/auth/roblox진입 → Roblox 동의 화면 이동 - 동의 후 콜백에
code/state수신 - 서버에서
/v1/token교환 성공(HTTP 200) access_token으로/v1/userinfo호출(정상 응답)/v1/token/resources로 리소스 범위 확인(권한 모델 매핑)/v1/token/revoke로 철회 후, 동일 토큰 재사용 시 실패 확인
728x90
그리드형(광고전용)
댓글