Fastify JWT 사용

byron1st·2021년 8월 17일
1

Fastify 사용기

목록 보기
3/3

Fastify 에 JWT 를 추가하는 것은 아주 쉽다. 개인적으로 지금까지 써본 서버 프레임워크들(express, koa, fastify, gin-gonic 등) 중에서 가장 쉬운 것 같다.

Fastify JWT

비교적 최근에 만들어진 모던 웹서버 프레임워크인만큼, JWT도 Fastify 팀에서 공식 지원한다. fastify-jwt 패키지를 설치하자. 미들웨어 설정은 아주 간편하다.

import jwt from 'fastify-jwt'

const server: FastifyInstance = fastify()

server.register(jwt, { secret: JWT_SECRET })

JWT 를 검증하고, 생성하는 것은 모두 server 객체의 jwt 프로퍼티를 통해 가능하다.

function authenticateByJWT(server: FastifyInstance, request: FastifyRequest) {
  //...
  const tokenStr = 'e...' // 헤더 등에서 추출한 토큰 스트링 값
  const payload = server.jwt.decode<PayloadType>(tokenStr)
}

decode 는 제너릭 함수로, <> 에 JWT의 Payload 타입을 지정해줄 수 있어 편리하다. 토큰을 생성하는 함수인 sign 도 편리하게 아래와같이 사용이 가능하다.

export async function createJWT(server: FastifyInstance, request: FastifyRequest) {
  // ...
  const payload: PayloadType = { ... }
  const tokenStr: string = server.jwt.sign(payload)
}

sign 함수의 두번째 파라미터에 옵션 객체를 넣을 수 있는데, 이를 통해 exp 값 등을 조절할 수 있다.

const tokenStr: string = server.jwt.sign(payload, { expiresIn: '1y' })

다양한 설정이 가능하니, 자세한 내용은 fastify-jwt 패키지의 저장소를 참고하자.

TypeScript 지원

express도 그렇고, fastify도 마찬가지로, 미들웨어는 일종의 함수 체인이다. 등록된대로, 앞 함수가 실행되고, 다음 함수가 실행되는 형태다. 그래서 미들웨어 형태로 JWT 인증을 구현하면, 인증된 내용(흔히 JWT payload 라고 부르는)을 request 객체에 붙여서 API 함수로 보내게 된다. 예를 들면, 아래와 같다.

function authenticateByJWT(server: FastifyInstance, request: FastifyRequest) {
  //...
  const tokenStr = 'e...' // 헤더 등에서 추출한 토큰 스트링 값
  const payload = server.jwt.decode<PayloadType>(tokenStr)
  request.raw.userID = payload.userID // Fastify는 `raw` 속성에 사용자 커스텀 속성을 저장한다
}

(참고로, Fastify 의 미들웨어 함수는 첫번째 파라미터로 FastifyInstance 를 받을 수도 있고, FastifyRequest를 받을 수도 있다. JWT 를 사용할 경우, FastifyInstancejwt 속성이 있기 때문에, 첫번째 파라미터로 FastifyInstance를 받도록 해야 한다.)

이때, raw 속성이 userID를 갖도록 정의되지 않아서, TypeScript 파서가 에러를 출력하는 경우가 있다. 이를 피하기 위해, 우리 서버에서 사용할 Request 객체 타입을 별도로 정의해서, FastifyRequest 대신 사용하면 된다.

import http from 'http'

interface RequestWithAuth extends http.IncomingMessage {
  userID?: string
}

export type AuthenticatedRequest<T extends RouteGenericInterface = RouteGenericInterface> = FastifyRequest<T, RawServerDefault, RequestWithAuth>

function authenticateByJWT(server: FastifyInstance, request: AuthenticatedRequest) {
  //...
  const tokenStr = 'e...'
  const payload = server.jwt.decode<PayloadType>(tokenStr)
  request.raw.userID = payload.userID // 타입 문제 없이 사용가능
}
profile
Hyperledger Fabric, React/React Native, Software Architecture

0개의 댓글