본문 바로가기
  • 프론트엔드 개발자 세오세오 | Frontend dev Seo
Learn to Code

[TIL] JWT 토큰 만들기, 토큰 유효기간 설정, 토큰 인증하기 (jsonwebtoken)

by CEOSEO 2021. 5. 28.
728x90
반응형

 

반짝반짝

 

 

클라이언트가 웹 서비스를 이용할 땐 서버와 다양한 통신을 주고 받는다. 서버가 클라이언트로부터 권한이 필요한 요청을 받았을 때, 이 요청을 요구한 유저가 그러한 권한이 있는지 등을 확인할 때 쓰일 수 있는 것이 바로 토큰(token)이다.  토큰을 사용한 인증은 세션 기반 인증보다 서버나 DB에 행해지는 번거로움이 줄어들고, 클라이언트에서 인증 정보를 보관하기 때문에 보다 간편하다는 장점이 있다.

 

 

 

 

 

JWT(JASON Web Token)는 여러 토큰 방식들 중 가장 많이 사용된다. (홈페이지: https://jwt.io/) 홈페이지에 방문해보면 상단 메뉴에 Libraries 탭이 있는데, 여기서 각종 언어별 라이브러리를 확인할 수 있다. 이번에 인증 관련 스프린트 공부를 하며 사용한 jsonwebtoken도 이곳에서 Node.js로 분류되어 있는 것을 볼 수 있다. jsonwebtoken API는 깃헙 레포에 상세하게 설명되어 있으며, 본 글 내용의 상당수도 해당 레포를 출처로 한다. 그럼 간단하게 jsonwebtoken을 설치하고 토큰 생성, 유효 기간 설정, 그리고 토큰 검증하기까지 진행해보도록 하겠다.

 

 

설치

npm install jsonwebtoken

 

 

토큰 생성: jwt.sign()

 

JWT 토큰을 생성하는 메소드는 sign()이다. sign()은 콜백과 함께 비동기적으로 호출되었을 땐 에러와 스트링화된 JWT 토큰을 리턴한다. 콜백함수 없이 동기적으로 호출되었을 땐 JWT 토큰만 리턴한다.

 

jwt.sign ( payload , secretKey , options , callback )

- payload: 객체 리터럴, 버퍼, 또는 JSON 스트링 등을 넣는다. 토큰에 담고 싶은 정보를 넣어주면 된다.

- secretKey: 일반 스트링이나 버퍼, 객체 등 암호화키를 넣어준다. 환경 변수를 사용할 수 있다.

- options: 필수가 아닌 옵션들을 객체 형태로 추가해준다. 암호화를 하는데 사용할 알고리즘을 바꾸거나 (디폴트는 HS256), 토큰의 유효시간 등을 선택할 수 있다.

- callback: 옵션과 마찬가지로 옵셔널한 항목이다. 만약 콜백이 추가된다면 비동기적으로 수행되며 에러와 토큰이 리턴된다. 콜백이 없을 경우엔 토큰만 리턴된다.

 

 

// 옵셔널한 인자들을 넣지 않고 디폴트 설정으로 만든 토큰의 예시.
// 매우 중요한 데이터를 담고 있으며, 문자열 탑시크릿키를 secretKey로 사용했다.

const jwt = require('jsonwebtoken')
const token = jwt.sign({data: "very important"}, 'topSecretKey')

 

 

// 옵션으로 사용된 암호화 알고리즘을 변경해주었고
// 콜백 함수를 넣어서 비동기 호출을 했다.
jwt.sign({
  data: "incredibly important", 
  'ilovedogs', 
  {algorithm: 'RS256'},
  (err, decoded) => console.log(token)
})

 

 

 

 

 

 

 

토큰 유효 기간 설정하기: 두 가지 방법

토큰의 유효기간은 토큰을 생성하는 시점에 (sign() 메소드를 작성할 때) 함께 설정해준다. 두 가지 방법이 있는데, 좀 더 어려운 방법과 쉬운 방법이 있다.

- 좀 더 어려운 방법: sign()의 인자 중 payload에 포함해주기

- 쉬운 방법: 옵션에 expiresIn으로 설정해주기

 

아래 두 예시는 API 설명에 나와있는 유효 시간 1시간을 설정하는 두 가지 방법이다. 똑같이 1시간의 유효시간을 주지만, 페이로드에 exp로 추가하는 것 보다 옵션에 expiresIn으로 추가하는 것이 시간 설정이 훨씬 편하기 때문에 추천되는 방식이다. expiresIn 옵션의 값을 줄 땐 숫자로 60*60과 같이 작성해도 되고, '7d', '2h', '3 days' 등과 같이 표현할 수도 있다.

 

// 좀 더 어려운 방법. Epoch time 기준으로 계산하기 때문에 이렇다
jwt.sign({
  data: "likewise very important",
  exp: Math.floor(Date.now()/1000) + (60*60)
  }, 'veryComplicatedSecreyKey')
  
// 쉬운 방법
jwt.sign({
  data: "too important that it's not dangerous",
  },
  'cuteDog',
  {expiresIn: '1h'}
)

 

 

토큰 검증하기: jwt.verify()

토큰을 통해 권한 인증이 요구될 때, 서버는 클라이언트로부터 받은 요청(req.headers.authorization)에서 토큰의 흔적을 찾는다.

 

토큰을 검증하는 메소드는 jwt.verify()이다. sign() 메소드와 마찬가지로 아주 간단하다! 서버는 verify() 메소드를 통해 우리 서버가 만들어낸 토큰이 맞는지 여부와, 혹시 만료된 것은 아닌지를 검증한다.

 

verify() 메소드는 sign()과 마찬가지로 콜백함수의 추가 여부에 따라 비동기/동기적으로 호출이 된다. 또한, 올바론 토큰이라는 것이 판정되면 해독된 payload를 리턴하지만, valid하지 않은 토큰일 경우엔 에러를 뿜는다.

 

jwt.verify ( token , secretKey , options , callback )

- token: 검증하고자 하는 토큰을 넣는다

- secretKey: 해당 토큰을 만들 때 사용한 비밀키를 넣는다. 이 비밀키로 해독이 되지 않는다면 짝퉁 토큰이라는 뜻이다.

- options: 옵셔널하게 넣을 수 있는 옵션들이다. 객체 형식으로 추가한다.

-callback: 옵셔널하게 넣을 수 있는 콜백 함수이다. 콜백함수를 추가하면 비동기로 호출되며 에러와 디코팅된 결과를 받는다.

 

 

const token = req.headers.authorization.split(' ')[1]
const data = jwt.verify(token, process.env.ACCESS_SECRET)

 

위 코드는 이번 토큰 스프린트를 하면서 verify() 함수를 실제 사용했던 예시이다. 요청(reg)의 헤더의 authorization에서 토큰 부분에 맞는 부분을 똑 때서 token 변수에 저장한 뒤, 이를 이용해 jwt(존맛탱)의 verify()메소드를 불러왔다. 비밀키로는 환경변수에 지정했던 ACCESS_SECRET이 사용되었다. (ACCESS.SECRET이라고 써서 한시간 넘게 해맸다...하아)

 

 

 

 

728x90
반응형

댓글