테마 전환

JWT와 Session 비교: 프로젝트에 맞는 인증 방식 선택하기

Easton editorial illustration: rendering-mode selector

커서가 session: { strategy: "jwt" }session: { strategy: "database" } 사이를 오갑니다. 프로젝트 출시가 코앞인데도 JWT와 Session 중 무엇을 써야 할지 결정하지 못한 상태입니다.

기술을 선택할 때 두 방식 모두 좋아 보이지만 어느 쪽이 내 프로젝트에 더 맞는지는 선뜻 판단하기 어렵습니다. JWT는 무상태이고 데이터베이스를 조회하지 않지만 즉시 폐기할 수 없습니다. Session은 상태를 유지하고 즉시 제어할 수 있지만 요청마다 데이터베이스를 조회해야 합니다. 이 글에서는 두 세션 전략의 차이와 선택 기준을 살펴봅니다.

먼저 JWT와 Session이 무엇인지 알아보기

JWT와 Session의 정의를 외우는 사람은 많지만, 막상 명확하게 설명하기는 쉽지 않습니다. 저는 다음과 같은 비유를 즐겨 씁니다.

Session은 헬스장 회원 카드와 같습니다. 회원으로 등록하면 헬스장은 시스템에 회원 정보를 기록합니다. 운동하러 갈 때마다 카드만 찍으면(Session ID를 제공하면) 프런트 직원이 시스템에서 회원의 신원, 이용 만료일, 남은 수업 횟수를 확인할 수 있습니다. 중요한 정보는 모두 헬스장 데이터베이스에 저장됩니다.

JWT는 신분증과 같습니다. 이름, 생년월일, 주소 같은 모든 정보가 증명서에 적혀 있습니다. 신원을 증명해야 할 때 신분증을 보여 주면 상대방은 별도의 시스템을 조회하지 않고도 누구인지 확인할 수 있습니다.

이렇게 보면 두 방식의 작동 원리가 명확해집니다.

  • Session 방식: 사용자가 로그인하면 서버가 Session ID를 생성하고 사용자 정보를 데이터베이스에 저장한 뒤, Cookie를 통해 Session ID를 브라우저로 보냅니다. 이후 요청마다 브라우저가 이 Session ID를 함께 보내면 서버는 데이터베이스에서 해당 사용자 정보를 조회합니다.

  • JWT 방식: 사용자가 로그인하면 서버가 사용자 정보를 암호화된 token(JWT)으로 묶어 브라우저로 직접 보냅니다. 이후 요청마다 브라우저가 JWT를 함께 보내면 서버는 데이터베이스를 조회하지 않고 token의 유효성만 검증합니다.

0회
JWT 데이터베이스 조회
이후 요청에서는 조회 불필요
매번
Session 데이터베이스 조회
요청마다 데이터베이스 조회
15분
JWT 권장 만료 시간
refresh token과 함께 사용
4KB
Cookie 크기 제한
JWT token이 너무 크면 안 됨
Source: 실무 경험 요약

JWT 자세히 알아보기

JWT가 인기 있는 이유

솔직히 JWT는 개발자 사이에서 상당히 인기 있으며, 특히 Serverless와 마이크로서비스를 다루는 팀에서 많이 사용합니다. 이유는 단순합니다. 데이터베이스를 신경 쓸 필요가 없기 때문입니다.

제 지인 한 명은 Vercel에 배포한 전자상거래 사이트를 만들면서 JWT를 선택했습니다. 그가 말한 JWT의 가장 큰 장점은 ‘편리함’이었습니다. 데이터베이스 연결 수가 부족할까 걱정할 필요도 없고, Session 테이블의 성능을 관리할 필요도 없으며, 엣지 노드에 배포해도 문제가 없다는 것입니다. 사용자가 한 번 로그인해 JWT를 받으면 이후 모든 요청에 이 token이 포함되고 서버는 서명만 검증하면 됩니다.

JWT는 특히 다음과 같은 환경에 적합합니다.

1. Serverless / 엣지 컴퓨팅
프로젝트를 Vercel이나 Cloudflare Workers 같은 플랫폼에 배포한다면 JWT가 거의 표준에 가깝습니다. 이런 플랫폼의 함수는 무상태이며 요청마다 서로 다른 서버에서 처리될 수 있습니다. Session을 사용하면 Session 데이터를 공유하기 위해 Redis까지 준비해야 하므로 번거롭습니다. JWT는 token 자체에 모든 정보가 들어 있어 어느 서버에서 처리해도 동일하게 작동합니다.

2. 높은 동시성 환경
대규모 할인 이벤트를 운영해 본 사람이라면 데이터베이스 조회가 성능 병목이라는 점을 잘 압니다. Session은 요청마다 데이터베이스를 조회하지만 JWT는 로그인할 때 한 번만 조회하고 이후 요청은 로컬에서 검증하므로 훨씬 빠릅니다.

3. 마이크로서비스 아키텍처
사용자 서비스, 주문 서비스, 결제 서비스처럼 여러 서비스가 있을 때 JWT를 사용하면 서비스끼리 인증 정보를 공유할 수 있습니다. 각 서비스가 사용자 Session을 따로 조회하거나 통합 Session 저장소를 구축할 필요가 없습니다.

JWT의 함정

아주 좋아 보이지만 JWT에도 문제가 있으며, 그중 일부는 상당히 까다롭습니다.

가장 큰 문제: 즉시 폐기할 수 없음

한번은 사용자 계정이 탈취된 사실을 확인하고 해당 사용자의 로그인 상태를 즉시 종료해야 했습니다. Session이었다면 데이터베이스 레코드를 삭제하면 끝났을 일입니다. 하지만 JWT를 사용하고 있어서 곤란했습니다. JWT는 한 번 발급하면 만료 전까지 유효하며 폐기할 수 없기 때문입니다.

블랙리스트를 만들면 되지 않느냐고 생각할 수 있습니다. 가능은 하지만 그러면 JWT의 무상태 장점을 잃습니다. 요청마다 블랙리스트를 확인해야 한다면 Session 테이블을 조회하는 것과 무엇이 다를까요?

따라서 JWT를 사용할 때는 보통 만료 시간을 15분 정도로 짧게 정하고 refresh token을 함께 사용합니다. 그러면 token을 탈취당하더라도 최대 15분 뒤에는 효력이 사라집니다.

Cookie 크기 제한

JWT는 사용자 정보를 모두 token에 인코딩합니다. 사용자 역할, 권한, 환경 설정 등을 너무 많이 넣으면 token이 매우 커집니다. 브라우저 Cookie에는 4KB 제한이 있어 이를 초과하면 저장할 수 없습니다.

여기서 얻을 수 있는 교훈은 모든 정보를 JWT에 넣지 말라는 것입니다. 사용자 ID와 만료 시간 같은 가장 기본적인 정보만 넣고, 나머지는 필요할 때 조회하세요.

NextAuth.js JWT 설정 실습

Next.js를 사용한다면 NextAuth.js(현재 명칭은 Auth.js)가 가장 인기 있는 인증 솔루션입니다. JWT 설정은 간단합니다.

// auth.ts
import NextAuth from "next-auth"
import GitHub from "next-auth/providers/github"

export const { handlers, signIn, signOut, auth } = NextAuth({
  providers: [GitHub],
  session: {
    strategy: "jwt",
    maxAge: 30 * 24 * 60 * 60, // 30일
  },
  callbacks: {
    async jwt({ token, user }) {
      // 최초 로그인 시 user 정보를 token에 추가
      if (user) {
        token.id = user.id
        token.role = user.role
      }
      return token
    },
    async session({ session, token }) {
      // token의 정보를 클라이언트에 노출
      if (token) {
        session.user.id = token.id
        session.user.role = token.role
      }
      return session
    },
  },
})

몇 가지 주의 사항이 있습니다.

  1. 반드시 NEXTAUTH_SECRET을 설정해야 합니다(Auth.js v5에서는 AUTH_SECRET으로 이름이 바뀌었습니다). npx auth secret으로 안전한 키를 생성할 수 있습니다. 이 키는 JWT 서명과 암호화에 사용되므로 절대 노출하면 안 됩니다.

  2. 롤링 세션: 사용자가 활동하는 동안 만료 시간을 자동으로 연장하려면 updateAge를 설정합니다.

session: {
  strategy: "jwt",
  maxAge: 30 * 24 * 60 * 60,
  updateAge: 24 * 60 * 60, // 24시간마다 한 번 갱신
}

이렇게 하면 사용자가 24시간 안에 활동하는 한 Session이 자동으로 연장되어 갑자기 로그아웃되지 않습니다.

  1. 2025년의 새로운 변화: Edge Runtime(예: middleware)에 배포하려면 설정을 분리해야 합니다.
// auth.config.ts - Edge에서 실행 가능
export default {
  providers: [GitHub],
  session: { strategy: "jwt" },
}

// auth.ts - 데이터베이스 작업을 포함하며 Node.js에서만 실행
import { PrismaAdapter } from "@auth/prisma-adapter"
import authConfig from "./auth.config"

export const { handlers, auth } = NextAuth({
  ...authConfig,
  adapter: PrismaAdapter(prisma),
})

Edge Runtime은 일부 Node.js API를 지원하지 않기 때문입니다. 설정을 분리하면 middleware에서는 auth.config.ts를 사용하고 서버 라우트에서는 전체 auth.ts를 사용할 수 있습니다.

Database Session 자세히 알아보기

반드시 Session을 사용해야 하는 경우

JWT가 편리하더라도 Session을 선택해야 하는 환경이 있습니다.

예전에 금융회사를 위한 백오피스 관리 시스템을 만든 적이 있습니다. 요구 사항은 명확했습니다. 비정상 로그인을 발견하면 언제든 사용자를 즉시 로그아웃시킬 수 있어야 한다는 것이었습니다. 이런 경우에는 JWT가 적합하지 않습니다.

Database Session은 다음과 같은 환경에 적합합니다.

1. 즉각적인 제어가 필요한 애플리케이션
여러 기기 로그인 제한(한 기기에서만 로그인 허용), 강제 로그아웃(관리자가 사용자 접속 종료), 비밀번호 변경 후 모든 로그인을 즉시 무효화하는 기능 등이 해당합니다. Session으로는 쉽게 구현할 수 있지만 JWT로 구현하려면 많은 추가 로직이 필요합니다.

2. 보안 요구가 높은 환경
은행, 의료, 정부 분야에서는 요청마다 최신 권한 상태를 확인해야 합니다. Session은 매 요청마다 데이터베이스에서 최신 정보를 조회할 수 있어 권한 변경 사항이 즉시 적용됩니다.

3. 전통적인 모놀리식 애플리케이션
서버와 데이터베이스가 함께 있는 전통적인 모놀리식 아키텍처라면 Session을 사용해도 큰 부담이 없습니다. 데이터베이스 조회 지연이 낮고 세션을 더 세밀하게 제어할 수 있습니다.

Session의 성능 문제

가장 큰 문제는 요청마다 데이터베이스를 조회해야 한다는 것입니다. 애플리케이션 트래픽이 많다면 병목이 될 수 있습니다.

다음과 같은 방법으로 최적화할 수 있습니다.

  1. Redis에 Session 저장: 전통적인 데이터베이스보다 훨씬 빠르고 자동 만료도 지원합니다.

  2. Session 정보 최소화: 사용자 ID만 저장하고 나머지 정보는 필요할 때 조회합니다.

  3. 적절한 만료 시간 설정: 만료된 Session을 제때 정리하지 않으면 Session 테이블이 계속 커집니다.

Next.js Session 설정 실습

NextAuth.js는 기본적으로 JWT를 사용합니다. Database Session을 사용하려면 adapter를 설정해야 합니다.

// auth.ts
import NextAuth from "next-auth"
import { PrismaAdapter } from "@auth/prisma-adapter"
import { PrismaClient } from "@prisma/client"
import GitHub from "next-auth/providers/github"

const prisma = new PrismaClient()

export const { handlers, auth } = NextAuth({
  adapter: PrismaAdapter(prisma),
  providers: [GitHub],
  session: {
    strategy: "database",
    maxAge: 30 * 24 * 60 * 60, // 30일
    updateAge: 24 * 60 * 60, // 매일 갱신
  },
})

Prisma에서는 Session 테이블을 만들어야 합니다. npx prisma db push를 실행하면 자동으로 생성됩니다.

// schema.prisma
model Session {
  id           String   @id @default(cuid())
  sessionToken String   @unique
  userId       String
  expires      DateTime
  user         User     @relation(fields: [userId], references: [id], onDelete: Cascade)
}

model User {
  id       String    @id @default(cuid())
  email    String    @unique
  sessions Session[]
}

성능 최적화 방법:

  1. sessionTokenexpires 필드에 인덱스를 추가하면 조회 속도가 훨씬 빨라집니다.

  2. 만료된 Session을 정기적으로 정리합니다. 예약 작업을 하나 만들 수 있습니다.

// cleanup-sessions.ts
async function cleanupExpiredSessions() {
  await prisma.session.deleteMany({
    where: {
      expires: {
        lt: new Date(),
      },
    },
  })
}

// 매일 새벽 3시에 실행

실무 선택 프레임워크

이론은 충분히 살펴봤습니다. 이제 무엇을 선택해야 할까요? 자신의 프로젝트에 대입해 볼 수 있는 선택 프레임워크를 정리했습니다.

프로젝트 유형에 따라 선택하기

프로젝트 유형권장 방식이유
Serverless 애플리케이션JWT무상태이며 공유 Session 저장소가 필요 없음
전통적인 모놀리식 애플리케이션Session데이터베이스가 가까워 조회 비용이 낮음
마이크로서비스 아키텍처JWT 또는 하이브리드서비스 간 인증이 편리함
콘텐츠 사이트/블로그JWT인증 요구가 단순해 JWT로 충분함
SaaS 백오피스Session세밀한 권한 제어가 필요함

보안 요구 수준에 따라 선택하기

  • 낮은 민감도(블로그, 포럼, 콘텐츠 사이트): JWT, 만료 시간 30일
  • 중간 민감도(전자상거래, 소셜 서비스): JWT + 짧은 만료 시간 + refresh token
  • 높은 민감도(금융, 의료, 백오피스): Session, 짧은 만료 시간 + 롤링 세션

실제 사례 분석

사례 1: 전자상거래 사이트 - JWT 선택

앞에서 언급한 지인의 전자상거래 사이트는 최종적으로 JWT를 선택했습니다. 이유는 다음과 같습니다.

  • Vercel에 배포한 Serverless 아키텍처라 JWT가 더 적합함
  • 사용자 수가 많아 데이터베이스 조회를 줄이면 비용을 절감할 수 있음
  • 세션 제어 요구가 높지 않아 사용자가 로그아웃한 뒤 token이 조금 늦게 만료되어도 수용 가능함

유일한 절충안은 JWT 만료 시간을 일반적인 30일 대신 7일로 설정한 것입니다. 계정을 탈취당하더라도 7일 뒤에는 token이 자동으로 만료됩니다.

사례 2: OA 시스템 - Session 선택

또 다른 프로젝트는 사내 OA 시스템이었으며 Session을 선택했습니다.

  • 엄격한 권한 관리가 필요해 역할 변경이 즉시 적용되어야 함
  • 동시 로그인 기기 수를 제한해야 함
  • 사내망 배포라 데이터베이스 조회 지연을 무시할 수 있음

이런 환경에는 Session이 확실히 더 적합합니다. Redis에 Session을 저장하는 최적화도 적용했으며 응답 시간은 50ms 이내로 충분했습니다.

사례 3: 하이브리드 방식 - Clerk의 접근법

현재 Clerk 같은 많은 인증 플랫폼은 하이브리드 방식을 사용합니다.

  • 단기 token(JWT): 유효 기간 15분, API 호출에 사용
  • 장기 token(Refresh Token): 데이터베이스에 저장하며 단기 token 갱신에 사용
  • Session 레코드: 데이터베이스에 활성 Session을 기록해 원격으로 폐기 가능

이렇게 하면 JWT의 성능상 이점과 Session의 제어 능력을 모두 얻을 수 있습니다. 다만 구현이 조금 복잡하므로 보안과 사용자 경험 모두에 높은 요구 사항이 있는 환경에 적합합니다.

제안하는 선택 기준

아직 확신이 없다면 다음과 같이 선택해 보세요.

  1. 기본적으로 JWT 사용: 대부분의 환경에서는 JWT로 충분하며 설정이 간단하고 성능도 좋습니다.

  2. 다음 상황에는 Session으로 전환:

    • 여러 기기 로그인 제한이 필요한 경우
    • 사용자를 즉시 로그아웃시켜야 하는 경우
    • 금융·의료처럼 보안 요구가 높은 경우
    • 비밀번호 변경 후 모든 로그인을 즉시 무효화해야 하는 경우
  3. 과도하게 설계하지 않기: 프로젝트 규모가 크지 않다면 단순한 방식으로 시작하고 실제 병목을 만났을 때 최적화하세요. 시작부터 하이브리드 방식을 적용했다가 코드 복잡도만 폭증하고 정작 기능은 거의 사용하지 않는 프로젝트를 너무 많이 봤습니다.

세션 만료 처리 모범 사례

방식을 선택한 뒤에는 세션 만료도 제대로 처리해야 합니다. 이 부분을 잘못 처리하면 사용자 경험이 크게 나빠집니다.

JWT 만료 처리

JWT 만료에서 가장 골치 아픈 상황은 사용자가 양식을 작성하다 제출하는 순간 ‘로그인이 만료되었습니다’라는 메시지가 나오고 입력한 내용이 모두 사라지는 것입니다. 매우 좋지 않은 경험입니다.

해결 방법: Refresh Token + 사용자에게 드러나지 않는 갱신

접근 방식은 다음과 같습니다.

  1. 사용자에게 두 개의 token을 발급합니다.

    • Access Token: 유효 기간 15분, API 호출에 사용
    • Refresh Token: 유효 기간 30일, 새 Access Token 발급에 사용
  2. 프론트엔드는 Access Token 만료가 가까워졌을 때(예: 2분 남았을 때) Refresh Token으로 새 Access Token을 자동 발급받습니다.

  3. 사용자는 이 과정을 전혀 인지하지 못하며 갑자기 로그아웃되는 일도 없습니다.

NextAuth.js에는 이 메커니즘이 내장되어 있어 다음과 같이 설정하면 됩니다.

callbacks: {
  async jwt({ token, user, account }) {
    if (account && user) {
      // 최초 로그인
      return {
        ...token,
        accessToken: account.access_token,
        accessTokenExpires: Date.now() + account.expires_in * 1000,
        refreshToken: account.refresh_token,
      }
    }

    // Access Token이 아직 유효함
    if (Date.now() < token.accessTokenExpires) {
      return token
    }

    // Access Token이 만료되어 Refresh Token으로 갱신
    return refreshAccessToken(token)
  },
}

async function refreshAccessToken(token) {
  try {
    const response = await fetch("https://api.example.com/oauth/token", {
      method: "POST",
      headers: { "Content-Type": "application/x-www-form-urlencoded" },
      body: new URLSearchParams({
        client_id: process.env.OAUTH_CLIENT_ID,
        grant_type: "refresh_token",
        refresh_token: token.refreshToken,
      }),
    })

    const refreshedTokens = await response.json()

    return {
      ...token,
      accessToken: refreshedTokens.access_token,
      accessTokenExpires: Date.now() + refreshedTokens.expires_in * 1000,
      refreshToken: refreshedTokens.refresh_token ?? token.refreshToken,
    }
  } catch (error) {
    return {
      ...token,
      error: "RefreshAccessTokenError",
    }
  }
}

Session 만료 처리

Session 만료 처리는 비교적 간단하지만 고려할 점이 있습니다.

롤링 세션과 절대 시간 제한

  • 롤링 세션: 사용자가 활동하면 세션을 연장하며 대부분의 환경에 적합합니다.
  • 절대 시간 제한: 사용자 활동 여부와 관계없이 정해진 시간이 되면 강제로 로그아웃하며 은행처럼 보안 요구가 높은 환경에 적합합니다.

NextAuth.js의 롤링 세션은 간단하게 설정할 수 있습니다.

session: {
  strategy: "database",
  maxAge: 2 * 60 * 60, // 2시간 절대 시간 제한
  updateAge: 30 * 60, // 30분 안에 활동하면 갱신
}

이 설정에서는 사용자가 30분 안에 활동하면 세션이 연장되지만, 어떤 경우든 2시간 뒤에는 강제로 로그아웃됩니다.

유휴 시간 제한

‘15분 동안 활동이 없으면 자동 로그아웃’을 구현하려면 프론트엔드에 타이머를 추가할 수 있습니다.

let idleTimer
function resetIdleTimer() {
  clearTimeout(idleTimer)
  idleTimer = setTimeout(() => {
    // 15분 동안 활동이 없으면 로그아웃
    signOut()
  }, 15 * 60 * 1000)
}

// 사용자 활동 감지
document.addEventListener("mousemove", resetIdleTimer)
document.addEventListener("keypress", resetIdleTimer)

2025년의 새로운 흐름

마지막으로 선택에 영향을 줄 수 있는 2025년의 흐름을 살펴보겠습니다.

하이브리드 방식이 주류로 부상

점점 더 많은 팀이 JWT와 Session을 양자택일의 관계로 보지 않습니다. 예를 들면 다음과 같습니다.

  • JWT로 API 인증(빠름)
  • 데이터베이스에 활성 Session 기록(제어 가능)
  • 두 방식의 장점 결합

Clerk와 Auth0 같은 인증 플랫폼도 이 방식을 사용합니다. 직접 구현하고 싶지 않다면 이런 서비스를 사용하는 것도 좋은 선택입니다.

Edge Runtime의 영향

Next.js의 middleware는 현재 Edge Runtime에서 실행되므로 JWT에 더 적합합니다. 전체 /dashboard 경로를 보호하는 것처럼 인증 로직을 middleware에 배치해야 한다면 JWT가 더 편리합니다.

Passkey와 WebAuthn

오늘의 핵심 주제는 아니지만 언급할 가치가 있습니다. Passkey(WebAuthn 기반)가 확산되면서 많은 사이트가 비밀번호 없이 지문이나 Face ID로 로그인하는 기능을 지원하기 시작했습니다. 이런 환경에서는 인증 과정이 더 복잡해지지만 사용자 경험은 좋아집니다. NextAuth.js v5는 이미 Passkey를 지원합니다.

마무리

이제 JWT와 Session을 비교할 기준이 어느 정도 분명해졌을 것입니다. 어느 쪽을 선택해야 한다는 정답은 없습니다. 각 방식의 장단점을 이해하고 프로젝트의 실제 상황에 맞춰 결정하는 것이 중요합니다.

제 경험상 대부분의 프로젝트에는 JWT로 충분하며, 즉각적인 제어가 필요한 상황에 Session을 고려하면 됩니다. 시작부터 너무 복잡하게 만들지 마세요. 단순한 방식이 오히려 더 안정적일 때가 많습니다.

그래도 망설여진다면 NextAuth.js의 기본 설정인 JWT로 먼저 시작하세요. 실제 문제가 생기면 Session으로 전환해도 어렵지 않으며 설정 몇 줄만 바꾸면 됩니다.

혹시 지금도 새벽 3시에 기술 선택을 고민하고 있나요? 그렇다면 일단 잠을 자고 다음 날 결정하기를 권합니다. 자고 일어나면 문제가 더는 문제가 아닌 경우도 많습니다(웃음).

이 글에 대한 의견이 있거나 여기서 다루지 않은 상황을 경험했다면 댓글로 알려 주세요. 기술은 함께 이야기할 때 더 재미있습니다.

FAQ

JWT와 Session의 핵심 차이는 무엇인가요?
JWT는 무상태 방식으로 사용자 정보가 token에 인코딩되며 서버는 서명만 검증하면 되므로 데이터베이스를 조회할 필요가 없습니다. Session은 상태를 유지하며 사용자 정보를 데이터베이스에 저장하므로 요청마다 조회해 검증합니다. JWT는 Serverless와 높은 동시성 환경에, Session은 즉각적인 제어가 필요한 환경에 적합합니다.
언제 JWT를 사용하고 언제 Session을 사용해야 하나요?
Serverless/엣지 컴퓨팅, 높은 동시성 환경, 마이크로서비스 아키텍처, 콘텐츠 사이트나 블로그에는 JWT를 사용합니다. 여러 기기 로그인 제한이나 강제 로그아웃처럼 즉각적인 제어가 필요하거나, 금융·의료처럼 보안 요구가 높거나, 전통적인 모놀리식 애플리케이션이라면 Session을 사용합니다. 기본적으로 JWT를 사용하고 즉각적인 제어가 필요할 때 Session으로 바꾸는 방식을 권장합니다.
JWT를 즉시 폐기할 수 없을 때는 어떻게 하나요?
JWT는 한 번 발급되면 만료 전까지 유효하므로 직접 폐기할 수 없습니다. 해결 방법은 1) 짧은 만료 시간(15분)과 refresh token을 함께 사용하거나, 2) 블랙리스트를 사용하거나(다만 무상태라는 장점을 잃습니다), 3) Session 또는 하이브리드 방식으로 전환하는 것입니다. 대부분의 환경에서는 짧은 만료 시간과 refresh token이면 충분합니다.
Session의 성능 문제는 어떻게 최적화하나요?
Session은 요청마다 데이터베이스를 조회하므로 병목이 될 수 있습니다. 1) 데이터베이스보다 훨씬 빠른 Redis에 Session을 저장하고, 2) Session 정보는 사용자 ID만 저장하도록 최소화하며, 3) sessionToken과 expires 필드에 인덱스를 추가하고, 4) 만료된 Session을 정기적으로 정리하면 됩니다.
NextAuth.js에서 JWT와 Session을 어떻게 설정하나요?
JWT는 session: { strategy: "jwt", maxAge: 30일 }로 설정하고 callbacks.jwt에서 사용자 정보를 추가합니다. Session은 PrismaAdapter와 session: { strategy: "database" }를 사용하며 Session 테이블을 만들어야 합니다. Edge Runtime 배포에는 설정 분리가 필요합니다.
세션 만료는 어떻게 처리하고 사용자 경험은 어떻게 개선하나요?
JWT는 Access Token(15분)과 Refresh Token(30일)을 사용해 사용자에게 드러나지 않게 갱신하고, 프론트엔드에서 만료 전에 자동으로 갱신합니다. Session은 롤링 세션(updateAge)을 사용해 사용자가 활동할 때 만료 시간을 연장합니다. 사용자가 양식을 작성하다 갑자기 로그아웃되어 데이터가 사라지는 상황을 피해야 합니다.
2025년 JWT와 Session에는 어떤 새로운 흐름이 있나요?
JWT로 API를 빠르게 인증하고 데이터베이스에 Session을 기록해 제어하는 하이브리드 방식이 주류가 되고 있습니다. Edge Runtime은 middleware 인증에 적합한 JWT에 더 우호적입니다. Passkey/WebAuthn도 확산되고 있으며 NextAuth.js v5는 이미 지원합니다. 실제 요구에 맞춰 선택하고 과도하게 설계하지 않는 것이 좋습니다.

3분 읽기 · 게시일: 2025년 12월 19일 · 수정일: 2026년 9월 4일

댓글

GitHub로 로그인하여 댓글을 남기세요

Easton BlogEaston Blog