JWT 개념 & 인증 흐름

HeeYeon Kim·2025년 6월 7일

STUDY

목록 보기
15/15
post-thumbnail

토큰 기반 인증 시스템

  • 클라이언트가 서버에 접속하면 서버에서 해당 클라이언트에게 인증되었다는 의미로 토큰을 부여하는 시스템
  • 토큰은 유일한 값이며 클라이언트는 서버에 요청 보낼 시 요청 헤더에 토큰을 심어 보냄
  • 그러면 서버는 이 토큰을 서버에서 제공한 토큰과의 일치 여부를 체크해 인증 과정을 처리함
  • 토큰 인증 순서
    1. 사용자가 아이디, 비밀번호로 로그인
    2. 서버 측은 사용자에게 토큰 발급
    3. 사용자는 전달받은 토큰을 쿠키나 스토리지에 저장
    4. 서버에 요청 시 사용자는 이 토큰을 HTTP 요청 헤더에 포함시켜 전달
    5. 서버는 전달받은 토큰을 검증하고 요청에 응답함




JWT

JWT란?

  • 인증에 필요한 정보들을 암호화시킨 JSON 토큰
  • JSON 데이터를 Base64 URL-safe Encode 를 이용해 인코딩해 직렬화함
  • 토큰 내부에는 위변조 방지를 위해 개인키 통한 전자서명도 있음
  • 사용자가 서버로 JWT 전송 시 서버는 해당 서명을 검증하는 과정을 거침
  • 제 3자에게 토큰 탈취의 위험성이 있기 때문에 AccessToken, RefreshToken으로 나누어 인증하는 방식을 취함
  • JWT 인코딩/디코딩은 JWT.IO에서 연습 가능

JWT의 구조

  • 일반적으로 아래의 구조를 지니며 왼쪽부터 Header, Payload, Signature를 의미함

    xxxx.yyyy.zzzz
  • Header : 토큰 유형 + 사용중인 서명 알고리즘으로 구성됨

    {
       "alg": "HS256",
       "typ": "JWT"
     }
    • Base64Url로 인코딩되어 xxxx 부분을 구성함

    • 서명 알고리즘은 SHA256, RSA 등이 있음

    • 헤더에서 설정한 서명 알고리즘은 아래 Signature가 사용할 알고리즘 방식

  • Payload : 토큰에서 사용할 정보 조각들인 Claim이 담겨 있음

    {
    	"iss": "https://auth.myapp.com",       // Registered Claim - 토큰 발급자
    	"sub": "user_12345",                   // Registered Claim - 사용자 ID
    	"aud": "https://api.myapp.com",        // Registered Claim - 토큰 대상
    	"exp": 1718000000,                     // Registered Claim - 만료 시간 (UNIX timestamp)
    	"iat": 1717996400,                     // Registered Claim - 발급 시간
    	"jti": "jwt-abcde-12345",              // Registered Claim - JWT 고유 식별자
    
    	"email": "jisu@example.com",           // Public Claim - 일반 사용자 정보
    	"name": "Kim Jisu",                    // Public Claim - 사용자 이름
    	"https://myapp.com/user-preferences": {  // Public Claim - 네임스페이스 지정
      		"theme": "dark",
      		"language": "ko"
    	},
    
    	"role": "ROLE_USER",                   // Private Claim - 내부에서만 해석 가능한 사용자 권한
    	"userId": "12345",                     // Private Claim - 서비스 내부 사용자 ID
    	"isPremium": true                      // Private Claim - 프리미엄 사용자 여부
    }
    • Claim : key-value 형식으로 이루어진 한 쌍의 정보
    • 보통 Registered claims, Public claims, Private claims 타입으로 나뉨
      • Registered claims : 미리 정의된 클레임
        • 예시 : iss(발행자), exp(만료시간), sub(제목), iat(발행시간), jti(JWI ID)등
      • Public claims : 사용자가 정의할 수 있는 클레임 공개용 정보 전달 위해 사용
        • 중복 피해 URI 형식 네임스페이스 권장
        • email, name 같이 공개 가능하지만 인증/인가 로직에 사용되지 않는 정보 저장
      • Private claims : 해당하는 당사자들간 정보 공유 위해 만들어진 사용자 지정 클레임
        • 외부에 공개되도 상관없지만 해당 유저를 특정할 수 있는 정보를 담음
        • 내부 로직에 필요한 정보를 커스텀하여 담는 용도로 쓰임
    • 서버-클라이언트 시스템에서 실제로 사용될 정보 내용을 담고 있음
  • Signature : Header + Payload와 서버가 갖고 있는 유일한 key값Header에서 정의한 알고리즘으로 암호화




AccessToken / RefreshToken

AccessToken

  • 클라이언트가 갖고 있는 실제 유저 정보가 담긴 토큰
  • 서버에서 해당 토큰에 있는 정보를 활용해 사용자 정보에 맞게 응답을 진행함

RefreshToken

  • 새로운 AccessToken을 발급하기 위해 사용하는 토큰
  • 보통 데이터베이스에 유저 정보와 같이 기록됨

왜 RefreshToken이 필요한가? : AccessToken은 보안에 취약하다!

  • 서버에 저장되지 않고 클라이언트에 저장됨
  • 그래서 탈취되면 만료 전까지 누구나 권한 접근 가능
  • 그래서 유효기간을 짧게 하고 RefreshToken의 유효기간을 길게 해 재발급을 편리하게 할 수 있도록 함




AccessToken/RefreshToken 재발급 원리

  1. 로그인하면 AccessToken, RefreshToken 모두 발급됨

    • RefreshToken만 서버 측 DB에 저장됨
    • AccessToken, RefreshToken을 쿠키 혹은 웹스토리지에 저장함
  2. 인증 필요한 API 요청 시 토큰 검사 진행

    case동작
    AccessToken, RefreshToken 모두 만료재로그인해 새로 발급
    AccessToken만 만료됨RefreshToken 검증 후 AccessToken 재발급
    RefreshToken만 만료됨AccessToken 검증 후 RefreshToken 재발급
    두 토큰 모두 유효함정상 처리
  3. 로그아웃 시 두 토큰 모두 만료 처리




JWT 인증 흐름

  1. 사용자가 ID, PW 이용해서 로그인함

  2. 서버에서 회원 DB에 저장된 값과 비교

    • 보통 PW는 암호화해서 저장되어있음
  3. 로그인이 완료되면 AccessToken, RefreshToken을 발급함

    • RefreshToken은 회원 DB에 저장됨
  4. 사용자는 RefreshToken은 쿠키나 웹스토리지에 저장하고 AccessToken을 요청 Header에 보내 요청 보냄

  5. AccessToken에 대한 검증 진행 후 통과하면 맞는 데이터를 보냄

만약 AccessToken이 만료된 경우

  1. 사용자는 이전처럼 AccessToken을 요청 Header에 보내 요청 보냄

    • Authorization 필드에 작성해서 요청 보냄

    • 보통 Bearer 토큰 방식으로 사용됨

    • 예시

      형식 : Authorization: <인증방식> <자격증명>
      
      Authorization: Bearer 123456(AccessToken위치)
      
  2. 서버는 AccessToken이 만료됨을 확인하고 권한없음을 신호 보냄

  3. 사용자는 RefreshToken과 AccessToken을 함께 서버에 보냄

  4. 서버는 RefreshToken을 사용자 DB에 저장된 토큰값과 일치하는지 비교 후 일치하고 유효 기간이 지나지 않았을 경우 새 AccessToken을 발급해줌

  5. 서버는 새로운 AccessToken을 Header에 실어 다시 API 요청 진행

  6. 사용자는 새 AccessToken을 받은 후 새 API 요청을 보냄

















참고 링크

JWT란 무엇이며 어떤 흐름을 가질까?
🌐 JWT 토큰 인증이란?(쿠키 vs 세션 vs 토큰)
Developing token authentication using ASP.NET Core

0개의 댓글