본문으로 건너뛰기
김신건의 로그

[DRF] Authentication: Session, Token, JWT, OAuth2

· 수정 · 📖 약 1분 · 391자/단어 #drf #authentication #jwt #session #token #oauth2
DRF authentication, TokenAuthentication, SessionAuthentication, BasicAuthentication, Simple JWT, django-rest-framework-simplejwt

정의

Authentication = 누가 요청했는지 식별. Authorization (django-drf-permissions) 과 별개.

흐름

flowchart LR
    Req[Request] --> Auth[Authentication class]
    Auth -->|성공| U[request.user = User 인스턴스]
    Auth -->|실패| Anon[request.user = AnonymousUser]
    Auth -->|잘못된 credential| Err[401]
    U --> Perm[Permission class]
    Perm -->|OK| View
    Perm -->|거절| Forbid[403]

자세한 permission 은 django-drf-permissions.

내장 Authentication Classes

Class방식
BasicAuthenticationHTTP Basic Auth
SessionAuthenticationDjango session (쿠키)
TokenAuthenticationDjango token (내장)
RemoteUserAuthentication웹 서버 인증

설정

# 전역
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.SessionAuthentication',
        'rest_framework.authentication.TokenAuthentication',
    ]
}

# View 별
class MyView(APIView):
    authentication_classes = [TokenAuthentication]

1. SessionAuthentication (Django 기본)

브라우저 세션 사용. Browsable API 에 필수.

authentication_classes = [SessionAuthentication]
  • 장점: Django 인증 시스템 그대로.
  • 단점: CSRF token 필요. 모바일/외부 앱 부적합.

2. TokenAuthentication (내장 토큰)

INSTALLED_APPS = [
    ...,
    'rest_framework.authtoken',
]
python manage.py migrate
# 토큰 발급 endpoint 등록
from rest_framework.authtoken.views import obtain_auth_token

urlpatterns = [
    path('api-token-auth/', obtain_auth_token),
]
# 사용
curl -X POST http://localhost:8000/api-token-auth/ \
  -d '{"username": "koa", "password": "secret"}' \
  -H 'Content-Type: application/json'
# → {"token": "abc123..."}

# 이후 요청
curl -H 'Authorization: Token abc123...' http://localhost:8000/api/users/
  • 장점: 단순.
  • 단점: 영구 토큰 (rotation 없음), revoke 어려움.

3. JWT (Simple JWT) - 사실상 표준

pip install djangorestframework-simplejwt
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    ],
}

SIMPLE_JWT = {
    'ACCESS_TOKEN_LIFETIME': timedelta(minutes=15),
    'REFRESH_TOKEN_LIFETIME': timedelta(days=7),
    'ROTATE_REFRESH_TOKENS': True,
    'BLACKLIST_AFTER_ROTATION': True,
    'ALGORITHM': 'HS256',
    'SIGNING_KEY': SECRET_KEY,
    'AUTH_HEADER_TYPES': ('Bearer',),
}
# urls.py
from rest_framework_simplejwt.views import (
    TokenObtainPairView, TokenRefreshView, TokenVerifyView,
)

urlpatterns = [
    path('api/token/', TokenObtainPairView.as_view()),
    path('api/token/refresh/', TokenRefreshView.as_view()),
    path('api/token/verify/', TokenVerifyView.as_view()),
]
# 로그인
POST /api/token/ {"username": "koa", "password": "..."}
 { "access": "eyJ...", "refresh": "eyJ..." }

# 요청
GET /api/users/ Authorization: Bearer eyJ...

# 갱신
POST /api/token/refresh/ {"refresh": "eyJ..."}
 { "access": "eyJ...", "refresh": "eyJ..." } rotation

# 검증
POST /api/token/verify/ {"token": "eyJ..."}

자세한 JWT 원리는 JWT.

Custom Claim

from rest_framework_simplejwt.serializers import TokenObtainPairSerializer

class MyTokenObtainPairSerializer(TokenObtainPairSerializer):
    @classmethod
    def get_token(cls, user):
        token = super().get_token(user)
        token['name'] = user.get_full_name()
        token['role'] = 'admin' if user.is_staff else 'user'
        return token

class MyTokenObtainPairView(TokenObtainPairView):
    serializer_class = MyTokenObtainPairSerializer

4. OAuth2 (django-oauth-toolkit)

pip install django-oauth-toolkit
INSTALLED_APPS = [..., 'oauth2_provider']

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'oauth2_provider.contrib.rest_framework.OAuth2Authentication',
    ],
}

자세한 OAuth2 는 OAuth2.

5. Custom Authentication

from rest_framework import authentication, exceptions

class ApiKeyAuthentication(authentication.BaseAuthentication):
    def authenticate(self, request):
        api_key = request.headers.get('X-API-Key')
        if not api_key:
            return None                # authentication 시도 안 함

        try:
            user = User.objects.get(api_key=api_key)
        except User.DoesNotExist:
            raise exceptions.AuthenticationFailed('Invalid API key')

        return (user, None)             # (user, auth) 튜플

    def authenticate_header(self, request):
        return 'X-API-Key'

비교 매트릭스

SessionToken (built-in)JWTOAuth2
설정최소간단중간복잡
Stateless하이브리드
Mobile부적합적합최적적합
Revoke즉시DB 삭제어려움 (blacklist)refresh revoke
Rotation-
제3자 통합표준표준
사용처Browsable API간단 API현대 APISSO, 3rd party

다중 Authentication

# 첫 성공한 것 사용
authentication_classes = [
    JWTAuthentication,          # 1순위
    SessionAuthentication,       # fallback
    TokenAuthentication,         # fallback
]

CSRF 처리

flowchart LR
    S["SessionAuthentication"] -->|CSRF 검증| C["CSRF token 필수"]
    T["TokenAuthentication"] -->|CSRF 안 검증| N["Token 만"]
    J["JWTAuthentication"] -->|CSRF 안 검증| N
  • Session = CSRF token 필요.
  • Token/JWT = CSRF 없음 (stateless).

HTTPS 필수

IMPORTANT

Token / JWT / Session cookie 는 반드시 HTTPS. HTTP 는 탈취.

다른 프레임워크

Framework인증
DRFSession, Token, JWT (simple-jwt)
Spring SecuritySession, JWT, OAuth2 (내장)
RailsDevise
Expresspassport.js
FastAPIOAuth2 helpers

흔한 함정

WARNING

  1. SECRET_KEY 노출 = JWT 위조. .env 관리.
  2. Token 무한 저장 = 유출 시 영구 침입. JWT + short expire.
  3. JWT payload 민감 정보 = 누구나 decode 가능. sub (user_id) 만.
  4. CSRF 켜져있는 상태에서 SPA = fetch 실패. csrfmiddlewaretoken 첨부.

관련 위키

이 글의 용어 (5개)
[Auth] JWT: 구조, 서명, 만료, refresh tokenauth-security
정의 JWT (JSON Web Token) (RFC 7519) 은 base64url 인코딩된 JSON + 서명 형태의 self-contained token. 서버가 세션 저장 없…
[Auth] OAuth 2.0 / 2.1: Authorization Code + PKCEauth-security
정의 OAuth 2.0 (RFC 6749, 2012) 은 제3자 앱이 사용자 동의로 자원에 접근 하게 하는 권한 위임 프레임워크. 인증 (authentication) 이 아니라 …
[Auth] Session Cookie: HttpOnly, SameSite, Secure flagauth-security
정의 Session Cookie 는 서버가 발급한 임의 ID 를 쿠키에 보관. 매 요청 자동 첨부. 서버 측 세션 store (Redis, DB) 와 짝. [!IMPORTANT]…
[Django] 인증: User, login, permissionsdjango
정의 Django는 User 모델, 인증·세션, 권한·그룹을 기본 제공한다. 앱이 핵심. 비밀번호 해싱(PBKDF2, scrypt, Argon2), 세션, 권한, 그룹, 비밀번호…
[Django] DRF Permission, Throttle, Filterdjango
정의 DRF는 view 호출 전 인증(Authentication) → 권한(Permission) → 스로틀(Throttle) 순으로 검사. 각 단계가 통과해야 view 메서드 실…

💬 댓글

사이트 검색 / 명령어

검색

스크롤 = 확대/축소 · 드래그 = 이동 · 0 = 원래 크기 · ESC = 닫기