인증 흐름 시작
엔드포인트
GET /v1/oauth/authorize설명
OAuth 인증 흐름의 진입점입니다. 클라이언트가 사용자를 이 엔드포인트로 리다이렉트하면, DataGSM OAuth 서버가 검증 후 DataGSM 로그인 페이지로 안내합니다. 사용자가 로그인에 성공하면 redirect_uri로 Authorization Code가 전달됩니다.
PKCE 사용 권장
code_challenge와
code_challenge_method를 포함하면 Authorization Code 탈취 공격을 방지할 수 있습니다.
자세한 내용은 PKCE 가이드를 참고하세요.
요청 파라미터
모든 파라미터는 쿼리 스트링(Query String)으로 전달합니다.
| 파라미터 | 타입 | 필수 여부 | 설명 | 예시 |
|---|---|---|---|---|
client_id | String | 필수 | DataGSM에서 발급받은 클라이언트 ID | your-client-id |
redirect_uri | String | 필수 | 인증 완료 후 code를 전달받을 URI (사전 등록 필요) | https://your-app.com/callback |
response_type | String | 선택 | 응답 타입 (code 고정, 기본값 code) | code |
state | String | 선택 (권장) | CSRF 공격 방지용 임의 문자열. 콜백 시 그대로 반환됨 | randomString123 |
code_challenge | String | 선택 (PKCE) | PKCE Code Verifier를 SHA-256 해싱 후 Base64URL 인코딩한 값 | E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM |
code_challenge_method | String | 선택 (PKCE) | Challenge 생성 방법 (S256 권장, plain 지원) | S256 |
scope | String | 선택 | 요청할 OAuth Scope 목록 (공백으로 구분). 미지정 시 기본 사용자 정보 조회 흐름으로 처리 | self:read |
Scope 사용 방식
DataGSM OAuth의 기본 사용자 정보 조회 권한 범위는 self:read입니다. 이 권한으로 사용자 데이터 조회 엔드포인트에서 사용자 기본 정보와 학생 상세 데이터를 조회할 수 있습니다.
신규 OAuth 연동에서 사용자 본인 정보만 필요하다면 scope 파라미터를 생략할 수 있습니다. 명시적으로 표현하고 싶다면 scope=self:read를 전달하세요.
서드파티 애플리케이션이 직접 정의한 권한 범위를 요청해야 할 때만 해당 애플리케이션의 Application ID를 앞에 붙인 {applicationId}:{scopeName} 형식을 사용합니다. 여러 권한 범위를 요청하는 경우 공백으로 구분하며, URL에서는 공백을 %20으로 인코딩합니다.
응답
성공 응답 (302 Found)
DataGSM 로그인 페이지로 리다이렉트됩니다. 서버 내부적으로 인증 상태 토큰이 생성되어 로그인 페이지에 전달되며, 유효 시간은 10분입니다.
사용자가 로그인에 성공하면 아래 형태로 redirect_uri에 Authorization Code가 전달됩니다.
https://your-app.com/callback?code={authorization_code}&state={state}
| 파라미터 | 설명 |
|---|---|
code | Authorization Code (5분 유효, 일회성) |
state | 요청 시 전달한 state 값 (생략한 경우 포함되지 않음) |
오류 응답
| 상태 코드 | 설명 | 원인 |
|---|---|---|
400 Bad Request | 잘못된 요청 | response_type이 code가 아님, 등록되지 않은 redirect_uri, code_challenge 없이 code_challenge_method만 전달 |
401 Unauthorized | 인증 실패 | 존재하지 않는 client_id |
요청 예시
URL 구성 (PKCE)
// 1. PKCE code_verifier 생성
function generateCodeVerifier() {
const array = new Uint8Array(32);
crypto.getRandomValues(array);
const base64 = btoa(String.fromCharCode(...array));
return base64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
}
// 2. code_challenge 생성 (SHA-256)
async function generateCodeChallenge(verifier) {
const data = new TextEncoder().encode(verifier);
const hash = await crypto.subtle.digest('SHA-256', data);
const base64 = btoa(String.fromCharCode(...new Uint8Array(hash)));
return base64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
}
// 3. state 생성 및 저장
const state = crypto.randomUUID();
const codeVerifier = generateCodeVerifier();
const codeChallenge = await generateCodeChallenge(codeVerifier);
sessionStorage.setItem('oauth_state', state);
sessionStorage.setItem('oauth_code_verifier', codeVerifier);
// 4. 인증 URL 구성 후 리다이렉트
const params = new URLSearchParams({
client_id: 'your-client-id',
redirect_uri: 'https://your-app.com/callback',
response_type: 'code',
state,
scope: 'self:read',
code_challenge: codeChallenge,
code_challenge_method: 'S256',
});
window.location.href = `https://oauth.authorization.datagsm.kr/v1/oauth/authorize?${params}`;URL 구성 (scope 생략)
사용자 본인 정보만 조회하는 기본 흐름에서는 scope 파라미터를 생략할 수 있습니다.
const state = crypto.randomUUID();
sessionStorage.setItem('oauth_state', state);
const params = new URLSearchParams({
client_id: 'your-client-id',
redirect_uri: 'https://your-app.com/callback',
response_type: 'code',
state,
});
window.location.href = `https://oauth.authorization.datagsm.kr/v1/oauth/authorize?${params}`;URL 구성 (서드파티 권한 범위)
외부 애플리케이션이 자체 권한 범위를 정의한 경우에는 해당 애플리케이션의 Application ID를 포함해 {applicationId}:{scopeName} 형식으로 전달합니다.
const params = new URLSearchParams({
client_id: 'your-client-id',
redirect_uri: 'https://your-app.com/callback',
response_type: 'code',
scope: 'your-application-id:profile',
});
window.location.href = `https://oauth.authorization.datagsm.kr/v1/oauth/authorize?${params}`;콜백 처리 예시
// redirect_uri 페이지에서 code와 state 수신
const params = new URLSearchParams(window.location.search);
const code = params.get('code');
const returnedState = params.get('state');
// state 검증 (CSRF 방지)
const savedState = sessionStorage.getItem('oauth_state');
if (returnedState !== savedState) {
throw new Error('State mismatch - possible CSRF attack');
}
sessionStorage.removeItem('oauth_state');
// code로 토큰 교환 진행
const codeVerifier = sessionStorage.getItem('oauth_code_verifier');
sessionStorage.removeItem('oauth_code_verifier');
// → POST /v1/oauth/token 으로 교환다음 단계
Authorization Code를 발급받았다면, 토큰 교환을 진행하세요.