인증과 인가: OAuth 2.0과 JWT
인증과 인가 완벽 가이드
1. 인증 vs 인가
인증 (Authentication): 너는 누구니? 인가 (Authorization): 무엇을 할 수 있니?
2. OAuth 2.0
Authorization Code Flow
1. 사용자 → 클라이언트: 구글 로그인 클릭
2. 클라이언트 → 구글: 인증 요청
3. 사용자 → 구글: 로그인 + 권한 승인
4. 구글 → 클라이언트: Authorization Code
5. 클라이언트 → 구글: Code + Client Secret
6. 구글 → 클라이언트: Access Token
7. 클라이언트 → API: Access Token으로 요청
구현
from flask import redirect, request
import requests
CLIENT_ID = 'your_client_id'
CLIENT_SECRET = 'your_client_secret'
REDIRECT_URI = 'http://localhost:5000/callback'
@app.route('/login')
def login():
return redirect(
f'https://accounts.google.com/o/oauth2/v2/auth?'
f'client_id={CLIENT_ID}&'
f'redirect_uri={REDIRECT_URI}&'
f'response_type=code&'
f'scope=openid email profile'
)
@app.route('/callback')
def callback():
code = request.args.get('code')
# Access Token 요청
response = requests.post('https://oauth2.googleapis.com/token', data={
'code': code,
'client_id': CLIENT_ID,
'client_secret': CLIENT_SECRET,
'redirect_uri': REDIRECT_URI,
'grant_type': 'authorization_code'
})
access_token = response.json()['access_token']
# 사용자 정보 요청
user_info = requests.get(
'https://www.googleapis.com/oauth2/v1/userinfo',
headers={'Authorization': f'Bearer {access_token}'}
).json()
return f"Welcome, {user_info['email']}!"
3. JWT (JSON Web Token)
구조
Header.Payload.Signature
Header: {"alg": "HS256", "typ": "JWT"}
Payload: {"user_id": 123, "exp": 1234567890}
Signature: HMACSHA256(base64(Header) + "." + base64(Payload), secret)
구현
import jwt
from datetime import datetime, timedelta
SECRET_KEY = 'your-secret-key'
# 토큰 생성
def create_token(user_id):
payload = {
'user_id': user_id,
'exp': datetime.utcnow() + timedelta(hours=24)
}
return jwt.encode(payload, SECRET_KEY, algorithm='HS256')
# 토큰 검증
def verify_token(token):
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=['HS256'])
return payload['user_id']
except jwt.ExpiredSignatureError:
return None # 만료됨
except jwt.InvalidTokenError:
return None # 유효하지 않음
4. Refresh Token
@app.route('/login', methods=['POST'])
def login():
# 인증 성공
access_token = create_token(user_id, expires_in=15*60) # 15분
refresh_token = create_refresh_token(user_id, expires_in=30*24*60*60) # 30일
return {
'access_token': access_token,
'refresh_token': refresh_token
}
@app.route('/refresh', methods=['POST'])
def refresh():
refresh_token = request.json['refresh_token']
user_id = verify_refresh_token(refresh_token)
if user_id:
new_access_token = create_token(user_id)
return {'access_token': new_access_token}
else:
return {'error': 'Invalid refresh token'}, 401
결론
인증 방식 선택:
- 세션 기반: 전통적, 서버 상태 관리
- JWT: Stateless, 분산 시스템 적합
- OAuth 2.0: 소셜 로그인, 제3자 인증