Authorization 완벽 마스터
Authorization의 핵심 개념과 실전 활용법
학습 항목
본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.
이미지 로딩 중...
OAuth 2.0 완벽 가이드
OAuth 2.0의 핵심 개념과 인증 플로우를 실제 코드로 배워봅니다. Authorization Code Grant부터 Token 관리까지 중급 개발자를 위한 완벽 가이드입니다.
들어가며
이 글에서는 OAuth 2.0 완벽 가이드에 대해 상세히 알아보겠습니다. 총 12가지 주요 개념을 다루며, 각각의 개념에 대한 설명과 실제 코드 예제를 함께 제공합니다.
목차
- Authorization_Code_Grant_Flow
- Authorization_Code_Exchange
- Access_Token_사용
- Refresh_Token_갱신
- PKCE_Extension
- State_Parameter_검증
- Scope_권한_관리
- Token_저장_보안
- Token_만료_처리
- Client_Credentials_Grant
- JWT_Token_검증
- OAuth_에러_처리
1. Authorization Code Grant Flow
개요
OAuth 2.0의 가장 안전한 인증 방식으로, 인증 코드를 받아 액세스 토큰으로 교환하는 방식입니다.
코드 예제
// 인증 URL 생성
const authUrl = `https://oauth.provider.com/authorize?` +
`client_id=${CLIENT_ID}` +
`&redirect_uri=${REDIRECT_URI}` +
`&response_type=code` +
`&scope=read write` +
`&state=${randomState()}`;
window.location.href = authUrl;
설명
클라이언트가 사용자를 인증 서버로 리다이렉트하며, state 파라미터로 CSRF 공격을 방지합니다.
2. Authorization Code Exchange
개요
인증 서버로부터 받은 코드를 액세스 토큰으로 교환하는 과정입니다.
코드 예제
const response = await fetch('https://oauth.provider.com/token', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'authorization_code',
code: authCode,
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET,
redirect_uri: REDIRECT_URI
})
});
const { access_token, refresh_token } = await response.json();
설명
서버 측에서 안전하게 클라이언트 시크릿과 함께 코드를 토큰으로 교환합니다.
3. Access Token 사용
개요
발급받은 액세스 토큰을 사용하여 보호된 API 리소스에 접근합니다.
코드 예제
const userData = await fetch('https://api.provider.com/user', {
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json'
}
});
const user = await userData.json();
console.log('User info:', user);
설명
Bearer 토큰 방식으로 Authorization 헤더에 액세스 토큰을 포함하여 API를 호출합니다.
4. Refresh Token 갱신
개요
액세스 토큰이 만료되었을 때 리프레시 토큰을 사용하여 새로운 액세스 토큰을 발급받습니다.
코드 예제
const refreshAccessToken = async (refreshToken) => {
const response = await fetch('https://oauth.provider.com/token', {
method: 'POST',
body: new URLSearchParams({
grant_type: 'refresh_token',
refresh_token: refreshToken,
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET
})
});
return await response.json();
};
설명
사용자가 다시 로그인하지 않고도 리프레시 토큰으로 새로운 액세스 토큰을 받을 수 있습니다.
5. PKCE Extension
개요
모바일 앱이나 SPA에서 클라이언트 시크릿 없이 안전하게 OAuth를 사용하는 방법입니다.
코드 예제
const codeVerifier = base64URLEncode(crypto.randomBytes(32));
const codeChallenge = base64URLEncode(
crypto.createHash('sha256').update(codeVerifier).digest()
);
const authUrl = `https://oauth.provider.com/authorize?` +
`client_id=${CLIENT_ID}` +
`&code_challenge=${codeChallenge}` +
`&code_challenge_method=S256`;
설명
Code Verifier와 Challenge를 사용하여 인증 코드 탈취 공격을 방지합니다.
6. State Parameter 검증
개요
CSRF 공격을 방지하기 위해 state 파라미터를 생성하고 검증합니다.
코드 예제
const state = crypto.randomBytes(16).toString('hex');
sessionStorage.setItem('oauth_state', state);
// 콜백에서 검증
const urlParams = new URLSearchParams(window.location.search);
if (urlParams.get('state') !== sessionStorage.getItem('oauth_state')) {
throw new Error('Invalid state parameter');
}
설명
랜덤 state 값을 저장했다가 콜백에서 비교하여 요청의 유효성을 검증합니다.
7. Scope 권한 관리
개요
애플리케이션이 필요한 권한만 요청하여 사용자 데이터를 보호합니다.
코드 예제
const requestedScopes = ['user:read', 'repo:write', 'notifications'];
const authUrl = `https://oauth.provider.com/authorize?` +
`client_id=${CLIENT_ID}` +
`&scope=${requestedScopes.join(' ')}` +
`&response_type=code`;
// 받은 토큰의 scope 확인
const { scope } = await response.json();
console.log('Granted scopes:', scope.split(' '));
설명
필요한 최소 권한만 요청하고, 실제 부여된 scope를 확인하여 사용합니다.
8. Token 저장 보안
개요
액세스 토큰과 리프레시 토큰을 안전하게 저장하는 방법입니다.
코드 예제
// httpOnly 쿠키에 저장 (서버 측)
res.cookie('refresh_token', refreshToken, {
httpOnly: true,
secure: true,
sameSite: 'strict',
maxAge: 7 * 24 * 60 * 60 * 1000
});
// 메모리에만 저장
let accessToken = null;
설명
리프레시 토큰은 httpOnly 쿠키에, 액세스 토큰은 메모리에 저장하여 XSS 공격을 방지합니다.
9. Token 만료 처리
개요
API 호출 시 토큰 만료를 감지하고 자동으로 갱신하는 로직입니다.
코드 예제
const apiCall = async (url, options = {}) => {
const response = await fetch(url, {
...options,
headers: { ...options.headers, Authorization: `Bearer ${accessToken}` }
});
if (response.status === 401) {
accessToken = await refreshAccessToken(refreshToken);
return fetch(url, { ...options, headers: { Authorization: `Bearer ${accessToken}` }});
}
return response;
};
설명
401 에러를 감지하면 자동으로 토큰을 갱신하고 요청을 재시도합니다.
10. Client Credentials Grant
개요
서버 간 통신에서 사용자 개입 없이 인증하는 방식입니다.
코드 예제
const getServiceToken = async () => {
const response = await fetch('https://oauth.provider.com/token', {
method: 'POST',
body: new URLSearchParams({
grant_type: 'client_credentials',
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET,
scope: 'api:read'
})
});
return await response.json();
};
설명
백엔드 서비스가 API에 접근할 때 사용하며, 사용자 컨텍스트가 필요 없는 경우에 적합합니다.
11. JWT Token 검증
개요
받은 액세스 토큰이 JWT인 경우 서명을 검증하고 클레임을 확인합니다.
코드 예제
const jwt = require('jsonwebtoken');
const verifyToken = (token, publicKey) => {
try {
const decoded = jwt.verify(token, publicKey, { algorithms: ['RS256'] });
if (decoded.exp < Date.now() / 1000) {
throw new Error('Token expired');
}
return decoded;
} catch (error) {
throw new Error('Invalid token');
}
};
설명
공개키로 서명을 검증하고 만료시간(exp)을 확인하여 토큰의 유효성을 판단합니다.
12. OAuth 에러 처리
개요
OAuth 플로우에서 발생할 수 있는 다양한 에러를 처리합니다.
코드 예제
const urlParams = new URLSearchParams(window.location.search);
const error = urlParams.get('error');
if (error) {
const errorMessages = {
'access_denied': '사용자가 권한을 거부했습니다',
'invalid_scope': '요청한 scope가 유효하지 않습니다',
'server_error': '인증 서버 오류가 발생했습니다'
};
alert(errorMessages[error] || '알 수 없는 오류');
}
설명
인증 서버가 반환하는 표준 에러 코드를 파싱하여 사용자에게 적절한 메시지를 표시합니다.
마치며
이번 글에서는 OAuth 2.0 완벽 가이드에 대해 알아보았습니다. 총 12가지 개념을 다루었으며, 각각의 사용법과 예제를 살펴보았습니다.
관련 태그
#OAuth #Authentication #Authorization #JWT #Security