본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.
본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.
이미지 로딩 중...
AI Generated
2025. 11. 5. · 17 Views
OAuth 2.1 최신 기능 완벽 가이드
OAuth 2.1의 최신 보안 기능과 모범 사례를 초급 개발자를 위해 쉽게 설명합니다. PKCE, 토큰 관리, 그리고 실전에서 바로 사용할 수 있는 예제를 포함합니다.
들어가며
이 글에서는 OAuth 2.1 최신 기능 완벽 가이드에 대해 상세히 알아보겠습니다. 총 10가지 주요 개념을 다루며, 각각의 개념에 대한 설명과 실제 코드 예제를 함께 제공합니다.
목차
- PKCE_코드_챌린지_생성
- Authorization_Code_Flow_시작
- 인증_코드로_토큰_교환
- Refresh_Token_자동_갱신
- Bearer_Token_API_호출
- Token_만료_시간_체크
- State_파라미터_CSRF_방지
- Logout_토큰_무효화
- Scope_권한_요청
- 토큰_안전한_저장소_관리
1. PKCE 코드 챌린지 생성
개요
OAuth 2.1에서 필수가 된 PKCE(Proof Key for Code Exchange)의 코드 챌린지를 생성하는 방법입니다. 공개 클라이언트의 보안을 강화합니다.
코드 예제
async function generatePKCE() {
const verifier = crypto.randomUUID() + crypto.randomUUID();
const encoder = new TextEncoder();
const data = encoder.encode(verifier);
const hash = await crypto.subtle.digest('SHA-256', data);
const challenge = btoa(String.fromCharCode(...new Uint8Array(hash)))
.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
return { verifier, challenge };
}
설명
랜덤 문자열을 생성하고 SHA-256으로 해시한 뒤 Base64 URL 인코딩하여 코드 챌린지를 만듭니다. verifier는 저장하고 challenge는 인증 요청에 포함시킵니다.
2. Authorization Code Flow 시작
개요
PKCE를 포함한 OAuth 2.1 인증 코드 플로우를 시작합니다. 사용자를 인증 서버로 리다이렉트합니다.
코드 예제
async function startOAuthFlow() {
const { verifier, challenge } = await generatePKCE();
sessionStorage.setItem('code_verifier', verifier);
const params = new URLSearchParams({
response_type: 'code',
client_id: 'your-client-id',
redirect_uri: 'https://your-app.com/callback',
code_challenge: challenge,
code_challenge_method: 'S256'
});
window.location.href = `https://auth-server.com/authorize?${params}`;
}
설명
PKCE 값을 생성하고 verifier를 저장한 후, 인증 서버로 리다이렉트합니다. S256 방식으로 챌린지를 전달하여 보안을 강화합니다.
3. 인증 코드로 토큰 교환
개요
콜백에서 받은 인증 코드를 액세스 토큰으로 교환합니다. code_verifier를 함께 전송하여 PKCE를 완성합니다.
코드 예제
async function exchangeCodeForToken(code) {
const verifier = sessionStorage.getItem('code_verifier');
const response = await fetch('https://auth-server.com/token', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'authorization_code',
code: code,
redirect_uri: 'https://your-app.com/callback',
client_id: 'your-client-id',
code_verifier: verifier
})
});
return await response.json();
}
설명
저장해둔 code_verifier와 인증 코드를 전송하여 토큰을 받습니다. 서버는 verifier와 challenge를 검증하여 보안을 확인합니다.
4. Refresh Token 자동 갱신
개요
액세스 토큰이 만료되기 전에 refresh token을 사용하여 자동으로 새 토큰을 발급받습니다.
코드 예제
async function refreshAccessToken(refreshToken) {
const response = await fetch('https://auth-server.com/token', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'refresh_token',
refresh_token: refreshToken,
client_id: 'your-client-id'
})
});
const tokens = await response.json();
localStorage.setItem('access_token', tokens.access_token);
return tokens;
}
설명
refresh token을 사용하여 사용자의 재인증 없이 새로운 액세스 토큰을 발급받습니다. 토큰을 안전하게 저장하여 API 호출에 사용합니다.
5. Bearer Token API 호출
개요
발급받은 액세스 토큰을 Authorization 헤더에 포함하여 보호된 API를 호출합니다.
코드 예제
async function callProtectedAPI(endpoint) {
const token = localStorage.getItem('access_token');
const response = await fetch(`https://api.example.com${endpoint}`, {
method: 'GET',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
}
});
if (response.status === 401) {
await refreshAccessToken(localStorage.getItem('refresh_token'));
return callProtectedAPI(endpoint);
}
return await response.json();
}
설명
Bearer 토큰을 헤더에 포함하여 API를 호출합니다. 401 오류 시 자동으로 토큰을 갱신하고 재시도합니다.
6. Token 만료 시간 체크
개요
JWT 토큰의 만료 시간을 확인하여 사전에 갱신이 필요한지 판단합니다.
코드 예제
function isTokenExpiringSoon(token, bufferSeconds = 300) {
try {
const payload = JSON.parse(atob(token.split('.')[1]));
const expiryTime = payload.exp * 1000;
const currentTime = Date.now();
const timeUntilExpiry = expiryTime - currentTime;
return timeUntilExpiry < bufferSeconds * 1000;
} catch {
return true;
}
}
설명
JWT 토큰을 디코딩하여 만료 시간(exp)을 확인합니다. 만료 5분 전에 미리 갱신하도록 하여 API 호출 중 토큰 만료를 방지합니다.
7. State 파라미터 CSRF 방지
개요
state 파라미터를 사용하여 CSRF(Cross-Site Request Forgery) 공격을 방지합니다.
코드 예제
function startOAuthWithState() {
const state = crypto.randomUUID();
sessionStorage.setItem('oauth_state', state);
const params = new URLSearchParams({
response_type: 'code',
client_id: 'your-client-id',
redirect_uri: 'https://your-app.com/callback',
state: state
});
window.location.href = `https://auth-server.com/authorize?${params}`;
}
function validateState(returnedState) {
const savedState = sessionStorage.getItem('oauth_state');
return savedState === returnedState;
}
설명
랜덤 state 값을 생성하여 저장하고 인증 요청에 포함시킵니다. 콜백에서 동일한 값이 반환되는지 확인하여 공격을 차단합니다.
8. Logout 토큰 무효화
개요
로그아웃 시 서버에서 토큰을 무효화하고 로컬 저장소를 정리합니다.
코드 예제
async function logout() {
const token = localStorage.getItem('access_token');
try {
await fetch('https://auth-server.com/revoke', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
token: token,
client_id: 'your-client-id'
})
});
} finally {
localStorage.removeItem('access_token');
localStorage.removeItem('refresh_token');
sessionStorage.clear();
}
}
설명
서버의 revoke 엔드포인트로 토큰 무효화를 요청하고, 로컬에 저장된 모든 토큰과 세션 데이터를 삭제합니다.
9. Scope 권한 요청
개요
필요한 최소한의 권한(scope)만 요청하여 보안을 강화하고 사용자 신뢰를 얻습니다.
코드 예제
function requestSpecificScopes(scopes) {
const params = new URLSearchParams({
response_type: 'code',
client_id: 'your-client-id',
redirect_uri: 'https://your-app.com/callback',
scope: scopes.join(' '),
});
// 예: ['read:user', 'write:posts']
window.location.href = `https://auth-server.com/authorize?${params}`;
}
// 사용 예시
requestSpecificScopes(['read:user', 'read:email']);
설명
앱에 필요한 권한만 명확히 지정하여 요청합니다. 불필요한 권한을 요청하지 않아 사용자 개인정보를 보호하고 승인율을 높입니다.
10. 토큰 안전한 저장소 관리
개요
토큰을 안전하게 저장하고 관리하는 클래스입니다. XSS 공격으로부터 보호합니다.
코드 예제
class SecureTokenStorage {
static setTokens(accessToken, refreshToken) {
// HttpOnly 쿠키 사용 권장, 데모용 localStorage
localStorage.setItem('access_token', accessToken);
localStorage.setItem('refresh_token', refreshToken);
localStorage.setItem('token_timestamp', Date.now().toString());
}
static getAccessToken() {
return localStorage.getItem('access_token');
}
static clearTokens() {
localStorage.removeItem('access_token');
localStorage.removeItem('refresh_token');
}
}
설명
토큰을 중앙에서 관리하는 클래스를 만들어 일관성을 유지합니다. 프로덕션에서는 HttpOnly 쿠키나 서버 세션 사용을 권장합니다.
마치며
이번 글에서는 OAuth 2.1 최신 기능 완벽 가이드에 대해 알아보았습니다. 총 10가지 개념을 다루었으며, 각각의 사용법과 예제를 살펴보았습니다.
관련 태그
#OAuth #PKCE #Authorization #JWT #Security
이 카드뉴스가 포함된 코스
댓글 (0)
함께 보면 좋은 카드 뉴스
Istio 보안 완벽 가이드
마이크로서비스 환경에서 필수적인 Istio 보안 기능을 실무 중심으로 설명합니다. mTLS부터 인증, 인가까지 단계별로 학습하여 안전한 서비스 메시를 구축할 수 있습니다.
서비스 메시 완벽 가이드
마이크로서비스 간 통신을 안전하고 효율적으로 관리하는 서비스 메시의 핵심 개념부터 실전 도입까지, 초급 개발자를 위한 완벽한 입문서입니다. Istio와 Linkerd 비교, 사이드카 패턴, 실무 적용 노하우를 담았습니다.
EFK 스택 로깅 완벽 가이드
마이크로서비스 환경에서 로그를 효과적으로 수집하고 분석하는 EFK 스택(Elasticsearch, Fluentd, Kibana)의 핵심 개념과 실전 활용법을 초급 개발자도 쉽게 이해할 수 있도록 정리한 가이드입니다.
Grafana 대시보드 완벽 가이드
실시간 모니터링의 핵심, Grafana 대시보드를 처음부터 끝까지 배워봅니다. Prometheus 연동부터 알람 설정까지, 초급 개발자도 쉽게 따라할 수 있는 실전 가이드입니다.
분산 추적 완벽 가이드
마이크로서비스 환경에서 요청의 전체 흐름을 추적하는 분산 추적 시스템의 핵심 개념을 배웁니다. Trace, Span, Trace ID 전파, 샘플링 전략까지 실무에 필요한 모든 것을 다룹니다.