Session(세션)과 Token(토큰)의 차이는?

땡글이·2023년 1월 15일
15

Stateless 한 프로토콜 : HTTP

우선 HTTP의 프로토콜 상태에 알아보자. HTTP 는 stateless 한 특성 때문에 각 통신의 상태는 저장되지 않는다. 하지만 서비스에서는 어떤 유저가 기능을 사용하는지 특정할 수 있어야하는데 이를 위해서 세션(Session) 혹은 토큰(Token)이 사용된다.

유저가 로그인을 시도할 때 서버 상에서 일치하는 유저 정보를 찾았다면 인증 확인의 표시로 세션이나 토큰을 발급해준다. 세션과 토큰의 가장 큰 차이점은 세션은 데이터베이스 서버에 저장된다는 것이고, 토큰은 클라이언트 측에서만 저장된다는 것이다.

쿠키(Cookie) + 세션(Session)

쿠키에 ID, PW와 같은 중요한 정보가 아닌, 인증을 위한 별개의 정보를 세션 저장소에 저장하고, 클라이언트는 세션을 쿠키에 담아 서버에 요청한다. 서버는 세션 저장소에 있는 세션과 일치하는지 즉, 유효한 세션인지 확인 후 적절한 응답을 보내준다.

쿠키저장소는 어디에?
쿠키는 브라우저별로 다른 위치에 저장된다. Google Chrome은 "C:\Users\\AppData\Local\Google\Chrome\User Data\Default\Local Storage" 에 저장된다고 한다. 물론 OS마다 쿠키 위치가 달라질 것이다.
쿠키는 모든 HTTP 요청에 들어가는 헤더로써, 서버에서 HTTP 응답 메시지에 만료기간을 기입해 저장된 쿠키가 삭제되도록 할 수 있다.

1. 동작 과정

  • 클라이언트가 ID/PW로 서버에 로그인
  • ID/PW로 인증 후, 사용자를 식별한 특정 유니크한 세션 ID를 만들어 마치 자물쇠처럼 서버의 세션 저장소에 저장
  • 세션 ID를 특정한 형태로 클라이언트에 다시 반환
  • 이후 사용자 인증이 필요한 정보를 요청할 때마다 세션 ID를 쿠키에 담아 서버에 함께 전달
  • 인증이 필요한 API일 경우, 서버는 세션 ID가 세션 저장소에 저장된 것인지 즉 유효한 세션인지 확인
  • 유효한 세션이라면, 인증 완료 후 적절한 응답을 보내준다. 없다면 401 에러 반환

2. 문제점

  • 세션 ID, Cookie 등이 탈취된다면 세션 저장소를 전부 지워 해결 가능하지만, 탈취당하지 않은 정상적인 사용자도 모두 재인증을 해야하는 상황이 발생한다.
  • 무엇보다 HTTP의 가장 큰 특성 중 하나인 stateless한 특성을 위배하게 된다. stateless 특성은 서버에서는 클라이언트의 상태를 저장하지 않아야 하지만 세션 저장소라는 곳에서 클라이언트의 상태를 저장하게 되므로 stateful 한 상태가 된다.
    • 위의 내용이 문제가 되는 이유는 확장성에 있다. 1번 서버에서 로그인한 사용자가 다른 2번 서버로 요청하게 되면 2번 서버에서는 세션이 저장되어 있지 않아 유효하지 않은 세션으로 인식된다는 것이다.
    • 이런 문제를 해결하기 위해 세션 저장소를 별도로 외부에 두는 것이 가장 일반적인 방식이다. Redis가 세션 저장소로 가장 많이 사용된다.

3. 문제점 해결 방안

세션 클러스터링 (Session Clustering)

  • 세션 클러스터링으로 서버 간 로그인 정보가 담긴 세션을 공유하는 방법이 있지만, 실제 서비스와 관련없는 인프라적인 작업으로 서버 리소스를 많이 쓰게되는 단점이 있다.
  • 전체적인 서버 규모가 크지 않다면 나쁘지 않지만, MSA로 잘게 쪼개져 수십 수백개의 서버로 이루어진다면 단점이 극명하게 나타날 것이다.
  • 세션 클러스터링에는 방법이 여러 가지다. "WAS 구성", "외부에 세션 서버 구축", "세션 데이터그리드 구성" 방법이 있다.

스티키 세션 (Sticky Session)

  • 스케일 아웃 시 여러 서버에 세션 정보를 복사할 필요 없도록 특정 세션을 처음 처리한 서버에게 이후 같은 세션의 요청을 같은 서버가 처리하도록 하는 방식이다.
  • A 사용자가 A 서버에게 요청했다면, A사용자의 요청은 모두 A서버에서 처리하는 방식이다.
  • 이 방법의 문제점은 각 서버가 균일하게 요청을 처리할 수 없다는 점에 있다. 즉, 특정 서버에만 요청이 몰리는 상황이 발생할 수 있다. 부하가 균일하게 분산되지 않는다.

세션 스토리지 분리

  • 이 방식은 세션 스토리지를 외부 서버로 분리하는 방식이다. 이 때 사용되는 세션 스토리지 서버로 일반적인 Disk-Based DB (Mysql, PostgreSQL, MongoDB 등)을 사용할 수 있지만, 입출력이 잦은 세션 특성 상 I/O 성능이 느린 데이터베이스는 사용하기에 적합하지 않다.
  • 따라서 세션을 저장하는 저장소로는 In-Memory DB를 사용하는 것이 일반적이다. In-Memory DB 중 어떤 DBMS 를 사용하는 것이 좋을까? 세션 데이터는 Key-Value로 구성되어 있다. 따라서 세션을 저장할 때는 대표적인 Key-Value DB인 Redis와 Memcached 를 사용한다.

'다중 서버 환경에서의 세션 불일치 문제와 해결방법'에 대해서 자세히 다루는 글을 따로 포스팅하였다. 해당 포스팅 을 참고하면 될 듯하다.

토큰(Token) - JWT

JWT 토큰 방식은 웹표준(RFC 7519)로서 두 개체에서 JSON 객체를 사용하여 가볍고 자가수용적인(self-contained) 방식으로 정보를 안정성 있게 전달한다. (자가수용적이라는 의미는 JWT 안에 인증에 필요한 모든 정보를 자체적으로 지니고 있다는 의미이다)

1. 동작 과정

  • 사용자는 클라이언트에서 ID/PW를 통해 로그인을 요청한다.
  • 유효한 ID/PW라면, Access token & Refresh token을 발급한다.
  • 클라이언트는 전달 받은 토큰들은 localStorage에 저장한다.
  • 클라이언트는 헤더에 Access token을 담아 서버에 요청한다.
  • 서버에서는 Access token을 검증하고, 응답을 클라이언트로 보낸다.
    • Access token이 유효하지 않다면 Refersh token으로 Access token을 재발급한 뒤, access token을 리턴해준다.

2. JWT 구조


각 내용마다 구분하기 위한 . 구분자가 들어간다.

2-1. 헤더 (Header)

헤더는 두 가지 정보를 가진다.

  • typ - 토큰의 타입(JWT)
  • alg - 해싱 알고리즘
    • Signature 를 해싱하기 위한 알고리즘 지정

2-2. 내용 (Payload)

Payload에는 토큰에 담을 정보들이 존재하고, 여기에 담는 정보의 한 조각을 클레임(claim) 이라고 한다.

  • 클레임은 키 값 형태로 존재한다.
    • 클레임의 종류는 등록된(registered) 클레임, 공개(public) 클레임, 비공개(private) 클레임들이 있다.

등록된(registered) 클레임

  • 등록된 클레임들은 서비스에서 필요한 정보들이 아닌, 토큰에 대한 정보들을 담기 위하여 이름이 이미 정해진 클레임들이다. 등록된 클레임의 사용은 모두 선택적(optional)이며, 이에 포함된 클레임 이름들은 다음과 같다.
    • iss: 토큰 발급자 (issuer)
    • sub: 토큰 제목 (subject)
    • aud: 토큰 대상자 (audience)
    • exp: 토큰의 만료시간 (expiraton), 시간은 NumericDate 형식으로 되어있어야 하며 (예: 1480849147370) 언제나 현재 시간보다 이후로 설정되어있어야합니다.
    • nbf: Not Before 를 의미하며, 토큰의 활성 날짜와 비슷한 개념입니다. 여기에도 NumericDate 형식으로 날짜를 지정하며, 이 날짜가 지나기 전까지는 토큰이 처리되지 않습니다.
    • iat: 토큰이 발급된 시간 (issued at), 이 값을 사용하여 토큰의 age 가 얼마나 되었는지 판단 할 수 있습니다.
    • jti: JWT의 고유 식별자로서, 주로 중복적인 처리를 방지하기 위하여 사용됩니다. 일회용 토큰에 사용하면 유용합니다.

공개(public) 클레임

  • 공개 클레임들은 충돌이 방지된 (collision-resistant) 이름을 가지고 있어야 한다. 충돌을 방지하기 위해서는, 클레임 이름을 URI 형식으로 짓는다.
{
    "https://velopert.com/jwt_claims/is_admin": true
}

비공개 (private) 클레임
등록된 클레임도 아니고, 공개된 클레임도 아니다. 양측 간에(클라이언트 - 서버) 협의 하에 사용되는 클레임 이름들이다. 공개 클레임과는 달리, 이름이 중복되어 충돌이 될 수 있으니 사용할 때 유의해야 한다.

{
    "username": "velopert"
    "email": "velpert@nnn.com"
}

예제 Payload

{
    "iss": "velopert.com",
    "exp": "1485270000000",
    "https://velopert.com/jwt_claims/is_admin": true,
    "userId": "11028373727102",
    "username": "velopert"
}
  • 위의 예제는 2개의 등록된 클레임, 1개의 공개 클레임, 2개의 비공개 클레임으로 이루어져 있다.

2-3. 서명 (Signature)

Signature 이란 토큰을 인코딩하거나 유효성 검증을 할 때 사용하는 고유한 암호화 코드이다.

  • 서명 생성 과정
    • 헤더와 페이로드 값을 각각 BASE64 로 인코딩
    • 위에서 인코딩한 값을 비밀 키를 이용해 헤더에서 정의한 알고리즘으로 해싱
    • 위에서 해싱한 값을 다시 BASE64 로 인코딩

3. JWT의 장점

  • 인증에 필요한 정보가 토큰에 있기에 별도의 저장소가 필요없다.
    • 하지만, 보안성을 높이기 위해 Refresh Token을 사용하는 경우 별도의 저장소에 저장하면서 사용하는 경우도 있긴 하다.
  • Cookie와 Session 사용 시 문제점이였던 stateful 한 특성을 JWT 토큰 사용 시에는 stateless 하게 가져갈 수 있다. 즉, 서버는 클라이언트의 상태를 가질 필요가 없다.
  • HTTP 헤더에 넣어서 쉽게 전달 가능하다.
  • 확장성에 용이하다. MSA 환경에 적용하기 편하다.

4. JWT의 단점

  • 거의 모든 요청에 토큰이 포함되므로 트래픽 크기에 영향을 미칠 수 있다.
  • 토큰에 정보가 많아져 토큰의 크기가 커지면 네트워크에 부하를 줄 수 있다.
  • 페이로드는 암호화된 게 아니라 BASE64 로 인코딩된 것이므로, 중간에 토큰을 탈취하면 페이로드의 데이터를 모두 볼 수 있다.
  • 따라서 페이로드에는 중요 정보를 담아선 안된다.

5. JWT의 암호화 방식

JWT 토큰 생성 시, JWT 헤더와 페이로드 정보를 인코딩하고, 둘을 합친 문자열을 비밀 키로 서명한다. 이 때 대칭키 암호화, 비대칭키 암호화 방식을 사용할 수 있다.

5-1. 대칭키 암호화

암호화, 복호화 키가 같으면 대칭키 암호화 방식이라고 한다.

  • 같은 키를 사용해 암호화, 복호화를 수행하기 때문에 속도가 빠르다.
  • 대표적으로 HMAC 암호화 알고리즘이 있다.
    • HS256, HS384, HS512 .... 가 이에 해당하고, 뒤 숫자는 secret key의 최소 바이트 크기를 의미한다.
    • 기본적으로 단방향 암호화 알고리즘인 SHA-256 과 함께 쓰인다.
  • 값에 SHA-256를 적용해서 해싱 후 private key( == secret key , 대칭키 역할)로 암호화 한다.
  • private key를 알고있는 서버만 Signature 유효성 검증이 가능하다. 즉 JWT를 복호화 할 수 있다.

5-2. 비대칭키 암호화

암호화, 복호화 키가 다르면 비대칭키 암호화 방식이라고 한다.

  • 다른 키를 사용해 암호화, 복호화를 수행하기 때문에 속도가 느리지만, 대칭키 암호화에 비해 안전하다.
  • 대표적으로 RSA 암호화 알고리즘이 있다.
    • 마찬가지로, SHA-256 단방향 암호화 알고리즘과 함께 쓰인다.
  • 값에 SHA-256 을 적용해서 해싱 후 비밀키(private key)로 암호화한다.
  • 그리고 공개키(public key) 는 공개적으로 제공한다. 어떠한 서버든 이 공개키를 통해 JWT를 복호화할 수 있다.

5-3. 대칭키 암호화 vs 비대칭키 암호화

대칭키 암호화 방식 같은 경우, private key를 모르는 서버는 JWT의 유효성을 검증할 수 없다. 반대로 비대칭키 암호화 방식은 private key를 몰라도 public key를 통해 복화할 수 있기 때문에 JWT의 유효성을 검증할 수 있다.

대칭키 암호화 방식에서의 인증서버 구축하기

흐름을 살펴보자.

  1. 인증 서버가 클라이언트에게 JWT를 발급
  2. 클라이언트는 JWT와 함께 애플리케이션 서버에 요청
  3. 애플리케이션 서버는 인증 서버의 private key를 모르므로 JWT를 검증할 수 없음

각 애플리케이션 서버에 인증서버의 private key를 넣어놓으면 되긴한다. 하지만 MSA 환경에서 수많은 애플리케이션 서버가 존재하는데, scale-out 할때마다 매번 private key를 넣어줘야 한다.

비대칭키 암호화 방식에서의 인증서버 구축하기

흐름을 살펴보자.

  1. 인증 서버가 클라이언트에게 JWT를 발급
  2. 클라이언트는 JWT와 함께 애플리케이션 서버에 요청
  3. 애플리케이션 서버는 인증 서버의 public Key를 통해 JWT를 검증할 수 있음

각 애플리케이션 서버에 일일히 key를 넣어줄 필요가 없다. public key가 공개되어 있기 때문이다.

API Gateway가 존재한다면?

비대칭키 암호화 방식을 사용하면 매번 각 서버에서 필터나 인터셉터를 통해 JWT에 대한 검증을 수행할 것이다. 하지만 API Gateway가 존재하면 API GW에서만 검증하면 된다. API GW에서 public key를 통해 검증해도 되지만, 대칭키 방식을 사용해도 API GW에만 private key를 넣어주면 되므로 대칭키 방식의 문제점도 딱히 드러나지 않는다.

간단히 결론을 내려보면 API GW가 없다면 비대칭키 암호화 방식을 사용하는게 좋고, API GW가 존재한다면 어떤 방식을 쓰든 상관없을 것 같다는 생각이 든다.

6. Refresh Token

Refresh Token은 토큰이 탈취당할 경우를 대비해 사용되는 것이다. Access Token 만으로 공격자가 요청하는 것인지 정상적인 클라이언트가 요청하는 것인지 알 수 없기 때문이다.

Access Token은 언제든지 탈취될 수 있다고 가정하기 때문에 Access Token에는 중요한 정보를 담으면 안된다. 따라서 Access Token의 유효기간을 짧게 설정하고, Refresh Token의 유효기간을 길게 설정한다. 물론 Access Token의 유효기간 동안에는 공격에 노출되어 있지만, 피해를 최소화하기 위한 방법이다.

6-1. 동작 과정

  • Access Token이 탈취됐을 때 대비를 위해 Refresh Token 개념을 도입했다. 그런데 Access Token과 Refresh Token 모두 클라이언트에 저장되면 같이 탈취되는거 아닌가? 라는 생각이든다.
  • 그래서 Access Token을 로컬 스토리지 또는 세션 스토리지에 저장하고, Refresh Token은 쿠키에 저장하고 보안 옵션들(HTTP Only, Secure Cookies)을 활성화 한다.
  • 물론 Refresh Token은 서버에도 저장되있어야 한다.

HTTP Only Cookies

클라이언트에서 자바스크립트로 쿠키를 조회할 수 있는데 해당 옵션을 활성화 하면 브라우저에서 쿠키에 접근할 수 없으므로 XSS와 같은 공격으로부터 안전하다.

Secure Cookies

HTTP 프로토콜은 언제든지 패킷을 중간에 가로챌 수 있다. 그래서 보안개념을 추가한 HTTPS 프로토콜을 사용하여 데이터를 암호화해 통신한다.
문제는 HTTPS 로 전송되어야 할 정보가 휴먼에러로 인해 HTTP 로 전송될 때 가 있다.
그래서 HTTPS 프로토콜이 아닌 경우에는 쿠키를 전송하지 않도록 설정하는 옵션이다.

6-2. Refresh Token만 탈취되면?

  • 공격자는 탈취한 Refresh Token 으로 계속 Access Token을 생성해서 정상적인 사용자처럼 서버에 계속 요청할 수 있다.
  • 이를 대비해서 서버에서 추가 검증 로직으로 방어해야 한다.
    • DB에 사용자와 Access Token, Refresh Token 들을 매핑하여 저장한다.
    • 정상적인 유저의 Access Token이 만료된 경우
      • Access Token과 Refresh Token을 서버로 보내서 새 Access Token을 요청한다 → 서버에서는 DB에 저장된Access Token, Refresh Token쌍과 클라이언트에서 보낸 토큰 쌍들을 비교한다 → 일치하면 새 Access Token토큰을 발급해준다.
    • 공격자가 Refresh Toekn을 탈취한 경우
      • 공격자가 탈취한 Refresh Token으로 새 Access Token 생성 요청 → Access Token이 없이 요청하면 공격으로 간주 → 서버에서 Access Token , Refresh Token 폐기

7. JWT 와 Session 방식 비교

7-1. 사이즈

세션의 경우, Cookie 헤더에 세션 ID만 실어 보내면 되므로, 트래픽을 적게 사용한다. 하지만, JWT는 사용자 인증 정보와 토큰의 발급시각, 만료시각, 토큰의 ID 등 담겨 있는 정보가 세션 ID에 비해 비대하므로 세션 방식보다 훨씬 더 많은 네트워크 트래픽을 사용한다.
Why JWTs Suck as Session Tokens 게시물에 따르면, 단순히 JWT에 iss, sub, nbf, exp, iat, jti, typ 클레임만을 실었는데 304 바이트가 나왔다고 한다. 그에 비해 세션 ID는 단 6바이트. 50배가 넘는 트래픽 비효율이다.

7-2. 안정성과 보안성

  • 세션의 경우, 모든 인증 정보를 서버에서 관리하기 때문에 보안 측면에서 조금 더 유리하다. 설령 세션 ID가 해커에게 탈취된다고 하더라도, 서버 측에서 해당 세션을 무효처리하면 된다.
  • 하지만, 토큰의 경우는 그렇지 않다. 토큰은 서버가 트래킹하지 않고, 클라이언트가 모든 인증정보를 가지고 있다. 따라서 토큰이 한 번 해커에게 탈취당하면 세션과 비교했을 때 조금 복잡한 방식(위의 내용 참고)으로 해킹을 막아야한다.
  • 또한 JWT 특성 상 토큰에 실린 Payload가 별도로 암호화 되어있지 않으므로, 누구나 내용을 확인할 수 있다. 따라서 Payload에는 민감한 데이터를 실을 수 없다. 즉, Payload에 실을 수 있는 데이터가 제한된다.
  • 하지만 세션과 같은 경우에는 모든 데이터가 서버에 저장되기 때문에 아무나 함부로 열람할 수 없기에 저장할 수 있는 데이터에 제한이 없다.

7-3. 확장성

  • 그럼에도 불구하고 최근 모던 웹 어플리케이션이 토큰 기반 인증을 사용하는 이유가 바로 이 확장성이다.
  • 일반적으로 웹 어플리케이션의 서버 확장 방식은 수평 확장을 사용한다. 즉, 한 대가 아닌 여러 대의 서버가 요청을 처리하게 된다. 이때 별도의 작업을 해주지 않는다면, 세션 기반 인증 방식은 세션 불일치 문제를 겪게 된다. 이를 해결하기 위해서 Sticky Session, Session Clustering, 세션 스토리지 외부 분리 등의 작업을 해주어야한다.
  • 하지만, 토큰 기반 인증 방식의 경우 서버가 직접 인증 방식을 저장하지 않고, 클라이언트가 저장하는 방식을 취하기 때문에 이런 세션 불일치 문제로부터 자유롭다. 이런 특징으로 토큰 기반 인증 방식은 HTTP의 비상태성(Stateless)를 그대로 활용할 수 있고, 따라서 높은 확장성을 가질 수 있다.

수직확장과 수평확장에 대한 자세한 내용은 '수직 확장(Scale up) vs 수평 확장 (Scale out)' 포스팅을,
다중 서버 환경에서의 세션 불일치 문제는 '다중 서버 환경에서의 세션 불일치 문제와 해결방법' 포스팅을 참고하자.

7-4. 서버의 부담

  • 확장성과 어느정도 이어지는 내용이다. 세션 기반 인증 방식은 서비스가 세션 데이터를 직접 저장하고, 관리한다. 따라서 세션 데이터의 양이 많아지면 많아질수록 서버의 부담이 증가할 것 이다.
  • 하지만 토큰 기반 인증 방식은 서버 대신, 클라이언트가 인증 데이터를 직접 가지고 있다. 따라서 유저의 수가 얼마나 되던 서버의 부담이 증가하지 않는다. 따라서 서버의 부담 측면에서는 세션 기반 인증 방식보다는 토큰 기반 인증 방식이 조금 더 유리함을 알 수 있다.

7-5. Session 과 Token 의 차이점 정리

  • stateful과 stateless 하다는 측면에서 차이점이 존재한다. 이는 토큰이 탈취됐을 때, 서버에서 능동적으로 이에 대응하여 토큰을 폐기처리할 수 있냐 없느냐에 따라 직결된다.
  • Session 방식은 로그인한 유저의 세션 개수를 제한할 수 있다는 점에서도 차이가 있다.
  • JWT의 등장 배경을 살펴보면, 보안이 뛰어나서가 아니라, 마이크로 서비스 아키텍처(MSA)가 도입되면서 주목 받기 시작한 방식이다.
  • 아래 사진처럼 수천 수만가지의 서버 to 서버 통신이 이루어지는 아키텍처에서 중앙화된 사용자 식별 저장소를 통해 각 API 요청을 인증처리 해야한다면.. 인증 서버만 수백대가 필요할 것이다. 그렇다고 아무리 내부 서버 끼리의 통신이라고 인증을 제외할 순 없으니 JWT를 통해 인증을 진행하는 것이다.
  • 추가로 앱과 웹을 모두 서비스하는 서버인 경우 웹에서는 Session을 이용하고 앱에서는 토큰을 이용하는 방식으로 별개의 인증방식을 가져가는게 아니라, 두 환경 모두 토큰을 기반으로 인증하여 환경에 구애받지 않고 동일한 API를 이용할 수 있다.

8. 마무리 간단 정리

적은 용량과 보안문제점 존재

쿠키의 문제점을 해결

문제점

  • 상태를 저장해야 하므로, 즉 세션 정보를 저장하기위한 추가 저장소가 필요하고 이는 http stateless 특성을 위반한다.
  • 즉 로그인할때마다 세션 스토리지(추가 저장소)에 접근해서 확인해야 한다.
  • 스케일 아웃 시 여러 서버에 세션 정보를 복사해줘야 하는 작업이 필요하다.
  • 이를 해결하기 위한 개념인 스티키 세션, 세션 클러스터링이 등장했지만, 여전히 stateful 하다는 문제점을 해결하지 못했다.

JWT (토큰, Token)

  • 클라이언트의 상태를 들고 있을 필요 없이 토큰만으로 인증처리가 가능하다. 즉 stateless하다.
  • MSA에서 중앙화된 인증방식에 비해 유리하다.
  • 그런데 보안문제로 Refresh Token을 도입하면 결국 이를 저장하기위한 별도의 저장소가 필요한건 마찬가지이다. 즉 stateless 하지 않다.
  • 하지만 세션은 로그인할 때마다 저장소에 접근하지만, JWT는 토큰이 만료되었을때만 저장소에 접근하기 때문에 접근하는 횟수 자체는 훨씬 적다.
  • access token을 사용하는 기간 동안은 stateless 하지만, 만료되었을 때는 stateless 가 깨지게된다.
  • MSA 환경에서 유용하다.

Reference

https://velog.io/@znftm97/JWT-Session-Cookie-%EB%B9%84%EA%B5%90-sphsi9yh#span-stylecolor0b6e995-refresh-tokenspan
https://hudi.blog/session-based-auth-vs-token-based-auth/
https://kku-jun.tistory.com/44
https://velog.io/@sms8377/TIL-32-%EC%BF%A0%ED%82%A4%EC%99%80-%EC%84%B8%EC%85%98-%EA%B7%B8%EB%A6%AC%EA%B3%A0-%EC%B0%A8%EC%9D%B4%EC%A0%90

profile
꾸벅 🙇‍♂️ 매일매일 한발씩 나아가자잇!

0개의 댓글