
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
또한 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로 철회 후, 동일 토큰 재사용 시 실패 확인
댓글