[Next.js] API middleware로 JWT 검증하기

toto9602·2025년 3월 23일
1

Next.js를 사용하여 간단한 프로젝트를 진행해 보고 있습니다!

Next.js에 API를 바로 구현해 보는 것은 처음이라 이래저래 우당탕탕 진행하고 있지만..
최근에 API에 middleware를 적용하는 방법에 대해 마음에 드는 레퍼런스를 찾아, 본 포스팅에서 간단히 적용한 기록을 남겨보려 합니다!

참고 자료

How to Write Actual API Middleware for Next.js
Next.js Middlewares

Next.js의 Middlewares

Next.js의 공식 문서에도 Middleware를 사용하는 방법이 소개되어 있었는데요.

대체로 아래와 같이 middleware.ts 파일을 추가해서
middleware 기능과, middleware를 적용할 경로를 설정해 주는 방식이었습니다!

import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
 
// This function can be marked `async` if using `await` inside
export function middleware(request: NextRequest) {
  return NextResponse.redirect(new URL('/home', request.url))
}
 
// See "Matching Paths" below to learn more
export const config = {
  matcher: '/about/:path*',
}

아쉬운 점 ?

참고자료에서 언급한 해당 방식의 아쉬운 점은 크게 두 가지였습니다.

  1. middleware.ts 파일을 따로 정의해야 해서, middleware가 실제 API가 정의된 부분과 분리됨
  2. 이미 디렉토리별로 API가 구분된 상황에서, config에서 정규표현 등으로 다시 한 번 경로를 지정해야 한다는 점이 불필요하게 느껴짐

→ 참고자료의 저자가 제안한, middlware chaining 방식을 적용해 보기로 !

[ 코드 출처 ]

const middleware_1 = async (req, res, next) => {
  console.log('Running middleware 1')
  next()
};
const middleware_2 = async (req, res, next) => {
  console.log('Running middleware 2')
  next()
};
const hello = async (req, res) => {
  res.status(200).json({ message: 'Hello World.' })
};
export default handler(
  middleware_1,
  middleware_2,
  hello,
);

middleware 추가하기

위 방식을 써 보기 위해, 우선 간단한 middleware를 하나 작성해 보려고 합니다!
예시 코드는 쿠키에 포함된 JWT를 읽어, verify하여 payload에 포함된
userId를 조회하는 내용입니다.

Middleware type 등 일부 코드는 참고자료에서 발췌해 사용했습니다!

export interface AuthenticatedRequest extends NextApiRequest {
  requesterId: number;
}

export const authRequired = (): Middleware => async (req: NextApiRequest, res: NextApiResponse, next: NextFunction) => {
  const token = getTokenFromHeader(req.headers);

  if (token) {
    const payload = jwtService.verifyToken(token);
    
	// userId를 꺼내어 Request 객체에 심어주기
    (req as AuthenticatedRequest).requesterId = payload.id;

    next();
  } else {
    res.status(HttpStatus.UNAUTHORIZED).json({ error: "UNAUTHORIZED" });
  }
};

const getTokenFromHeader = (headers: IncomingHttpHeaders) => {
  const cookie = headers.cookie;

  if (!cookie) return null;

  const parsedCookie = parse(cookie);

  return parsedCookie?.token;
};

middleware를 API에 적용하기

API routes 파일에 적용해 보면..
아래와 같은 형태가 되겠네요!

// pages/api/groups/index.ts
// 그룹 조회 API
const groups = async (req: NextApiRequest, res: NextApiResponse) => {
  if (req.method === "GET") {
    const response = await getGroups(req);
    return res.status(HttpStatus.OK).json(response);
  }

  if (req.method === "POST") {
    const response = await createGroup(req);
    return res.status(HttpStatus.CREATED).json(response);
  }
};

export default handler(
  allowMethods(["GET", "POST"]),  // GET, POST만 허용하는 middleware![](https://velog.velcdn.com/images/toto9602/post/19702de6-f49e-4a53-83c2-7605f3ed7d94/image.png)

  authRequired(), // req에 userId를 담아주는 middleware 
  groups
);

확실히 이런 방식으로 작성하는 게 실행 흐름을 일목요연하게 보기 좋은 것 같네요!

GET 요청을 간단히 날려보면..

의도된 실행 흐름대로 동작하는 부분까지 확인!

마무리

Next.js API에 middleware를 한번 적용해 보았는데요!
요청 Validation 같이 middleware가 여러 개 추가되는 경우에 더 유용한 패턴일 것 같다는 생각도 드네요.
추후 프로젝트 진행에 따라 조금 더 적극적으로 사용해 볼 수 있을 것 같습니다~!

profile
주니어 백엔드 개발자입니다! 조용한 시간에 읽고 쓰는 것을 좋아합니다 :)

0개의 댓글

관련 채용 정보