프로젝트

Next.js Proxy와 Redis로 구현한 낙관적 권한 체크

DevPearl 2026. 5. 1. 18:06

안녕하세요.
프로젝트를 진행하며 인증/인가를 구현하는 과정에서 Next.js의 `proxy.ts`를 활용해 낙관적 권한 체크 기반 리다이렉트(optimistic authorization check)를 적용한 경험을 정리해보았습니다.

프론트엔드에서 1차적인 권한 기반 리다이렉트를 어디서, 어느 정도까지 처리할 수 있을지 고민하는 분들께 도움이 되었으면 합니다.

목차
1. Next.js `proxy.ts`에서의 권한 기반 리다이렉트
2. 동적으로 바뀌는 권한 정보를 JWT대신 Redis로 관리하기
3. 정리

 

1. Next.js proxy.ts에서의 권한 기반 리다이렉트


Next.js 공식 문서에서는 Proxy를 다음과 같이 소개한다.

Proxy는 요청이 완료되기 전에 실행되며, 들어온 요청을 기반으로 rewrite, redirect, request/response header 수정, 직접 응답 등을 처리할 수 있는 계층이다.

 

 

Next.js 공식 문서에서 Proxy는 권한 기반 리다이렉트 같은 optimistic check에 유용하다고 설명한다.

예를 들면 아래와 같다.

/projects/p3 접근
  ↓
proxy.ts에서 session 확인
  ↓
route-level permission 확인
  ↓
권한이 없으면 /403 또는 fallback route로 redirect

 

단, Proxy에서 전체 권한 제어 및 관리를 하는것은 지양해야 한다고 명시되어있다.

 

그렇다면 권한 시스템을 설계할 때 고려해야 하는 아래 주요 문제들과 Proxy의 접목 방법을 고민해봐야 한다.

- over-permissive: 권한을 너무 넓게 허용하여 생기는 보안 문제
- under-permissive: 권한을 너무 좁게 허용하여 생기는 사용자 경험 저하
- inconsistency: 여러 계층에서 권한을 각자 다르게 판단하며 일관성이 깨지는 문제
- unmaintainable: 권한 정보 또는 검증 로직이 여러 파일에 흩어져 유지보수가 어려워지는 문제

Proxy의 특성과 권한검증의 특성을 종합한 결과, 프론트엔드 관점에서의 일관성과 유지보수 용이성 측면에 집중하기로 했다.

각 페이지나 컴포넌트마다 직접 검사하지 않고 미들웨어로 권한 로직을 모아서 일관성을 높이고 업데이트에 용이한 장점을 살리는 방향이다.

따라서 아래와 같이 방향을 잡았다.

- Proxy에서는 로그인 여부와 간단한 라우트 레벨 권한을 빠르게 확인한다.
- 최종 권한 검사는 서버의 Data Access Layer에서 수행한다.

 

 

2. Proxy에서 동적인 권한 정보를 다루기 위해 JWT가 아닌 Redis를 고려한 이유


처음에는 session 또는 JWT에 들어있는 정보를 기반으로 Proxy에서 간단한 권한 체크를 수행하는 구조를 생각했다.
예를 들어 사용자의 role이 관리자인지 확인하거나, 현재 조직에 속해 있는지 확인하는 정도라면 token 기반으로도 충분했다.

하지만 “JWT의 생명주기와 관계없이 바뀔 수 있고, 변경 사항이 즉시 반영되어야 하는 정보”라는 요구사항이 추가 되는 경우 문제가 된다.
프로젝트와 다큐멘트가 분리된 프로젝트 문서관리 툴을 예시로 들면, 사용자가 접근 가능한 프로젝트 목록은 JWT의 수명과 관계없이 변경 가능하며 즉시 업데이트 되어야 한다.
사용자가 접근 가능한 `projectIds`가 다음과 같다고 해보자.

{
  "userId": "u1",
  "projectIds": ["p1", "p2", "p3"]
}
 

이 정보를 JWT에 그대로 담으면 구현은 단순하다. Proxy에서는 토큰을 읽고 현재 요청의 projectId가 projectIds에 포함되어 있는지만 확인하면 된다.

하지만 관리자가 사용자의 p3 프로젝트 접근 권한을 제거하더라도, 이미 발급된 JWT 안에는 여전히 p3가 남아 있을 수 있다. 토큰이 만료되기 전까지 stale한 권한 정보가 유지되는 것이다.

즉, 다음과 같은 정보는 JWT에 고정해서 넣기 어렵다.

  • 사용자가 접근 가능한 project 목록
  • project별 role
  • 권한 회수 또는 추가가 즉시 반영되어야 하는 permission 등

물론 Proxy에서 매 요청마다 API 서버나 DB에 접근해 최신 권한을 확인하는 방법도 있다. 하지만 Next.js 문서에서도 Proxy는 느린 data fetching을 위한 곳이 아니라고 설명하고 있으며.

또한 Proxy는 요청의 앞단에서 실행될 수 있기 때문에, 이곳에서 매번 API 요청을 수행하면 네트워크 레이턴시가 추가된다. 모든 요청에 대해 불필요한 권한 조회가 발생하지 않도록 예외 처리를 늘리다 보면 코드 복잡도도 올라간다.

 

크게 두 가지 선택지를 고민해볼 수 있었다.
1. 동적으로 바뀌는 project 접근 권한 검사는 Proxy에서 제거한다.
2. Redis를 도입해 Proxy에서 사용할 수 있는 가벼운 permission cache를 둔다.

 

결국 팀의 현재 상황과 기술 도입의 오버헤드 및 강점에 따라 판단은 달라질 것이다.

project 접근 권한을 주요 라우트에서 1차적으로 검증할 필요가 있다고 해서 항상 Redis가 정답은 아니다.

어떤 팀에서는 Redis 도입 및 관리 비용이 더 클 수 있다. 이 경우에는 Proxy에서 동적 권한 검사를 제거하고, 서버 또는 각 페이지 단위에서 권한을 검증하는 편이 더 단순할 수 있다.


반대로 기존 API 서버의 인증 레이어에서도 일부 권한 정보를 빠르게 조회하거나 갱신해야 하는 요구가 있다면, Redis를 도입해 여러 권한 정보를 함께 관리하는 편이 더 가치 있을 수 있다.

 

나의 경우는 여러 상황을 고려했을때 Redis 도입의 가치가 있다고 판단해서 팀에 제안했다.

projectId를 관리하는 예시로 대입해본다면 아래와 같이 관리할 수 있다. 

user:{userId}:projects = Set(projectId)
 

Proxy에서는 현재 요청의 projectId에 대해 Redis를 조회해 명백히 접근 불가능한 요청을 빠르게 redirect한다.

const canAccess = await redis.sismember(
  `user:${userId}:projects`,
  projectId
)

if (!canAccess) {
  return NextResponse.redirect(new URL('/403', req.url))
}
 

이 방식은 JWT에 project 목록을 직접 넣는 것보다 동적인 권한 변경에 더 유연하다.

권한이 추가되거나 회수되면 Redis를 갱신하면 되고, 다음 요청부터 변경된 권한 정보를 기준으로 Proxy에서 필터할 수 있다.

 

이 구조를 활용하면 Proxy의 장점인 빠른 권한 기반 리다이렉트를 활용하면서도, JWT에 동적인 권한 정보를 담았을 때 발생하는 stale data 문제를 해결할 수 있다.

Redis를 활용한다면 JWT의 stateless 의 이점을 포기하는 만큼 반대로 가져갈 수 있는 강점도 같이 가져가면서 리프레시토큰 발급, 로그아웃 시 토큰 소멸 등 여러 다른 기능을 활용하는 것도 좋을 것이다.

 

그리고 반드시 Redis 장애가 발생할 경우 대응 방향을 고려해야 한다.

Redis 장애가 발생할 경우 미들웨어 검증을 생략하고 서버단에서만 API fallback으로 처리하는 방법 등 여러 방법중 팀의 요구사항에 적합한 장애대응 방식을 세워야한다.

 

3. 정리

 

이번 구현에서 핵심은 Proxy와 Redis를 최종 권한 검사의 수단으로 사용하는 것이 아니라, 각 계층의 역할을 분리하는 것이었다.

- Proxy는 로그인 여부와 route-level permission을 빠르게 확인하는 필터 역할을 한다.
- Redis는 JWT에 담기 어려운 동적 권한 정보를 빠르게 조회하기 위한 권한 캐시 역할을 한다.
- 서버의 Data Access Layer는 실제 데이터 접근과 mutation에 대한 최종 권한 검사를 담당한다.

이 구조를 통해 접근 불가능한 라우트는 초기에 리다이렉트할 수 있고, project 권한처럼 동적으로 바뀌는 정보는 JWT의 생명주기에 묶이지 않게 관리할 수 있었다.

 

결국 Next.js의 Proxy에서 권한 체크가 가장 효과적으로 쓰이는 지점은, 모든 권한을 Proxy에서 처리할 때가 아니라, 서버의 최종 권한 검사를 전제로 1차적인 낙관적 권한 체크로 활용할 때라고 생각한다.

 

 

참고자료:

 

- [Next.js Docs - Authentication Guide] https://nextjs.org/docs/pages/guides/authentication#creating-a-data-access-layer-dal-1 

- [Upstash - Session Management in Next.js Using Redis] https://upstash.com/blog/session-management-nextjs

- [Next.js Docs - proxy.js] https://nextjs.org/docs/app/getting-started/proxy

- [Redis Blog - JSON Web Tokens are Dangerous for User Sessions] https://redis.io/blog/json-web-tokens-jwt-are-dangerous-for-user-sessions/?utm_source=chatgpt.com