Fastify 에 JWT 를 추가하는 것은 아주 쉽다. 개인적으로 지금까지 써본 서버 프레임워크들(express, koa, fastify, gin-gonic 등) 중에서 가장 쉬운 것 같다.
비교적 최근에 만들어진 모던 웹서버 프레임워크인만큼, 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
패키지의 저장소를 참고하자.
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 를 사용할 경우, FastifyInstance
에 jwt
속성이 있기 때문에, 첫번째 파라미터로 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 // 타입 문제 없이 사용가능
}