You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Next.js App Router应用中如何存储JWT Access Token?

关于JWT Access Token存储的问题(Next.js环境)

我有一个基于JWT认证的后端服务,登录时会在响应体返回Access Token,同时把Refresh Token存在Http-only Cookie里。我知道Refresh Token会自动附在每个请求上,但现在纠结Access Token的最优存储方式,目前遇到的限制是:

  • 不能用Local Storage或Cookie
  • 不想把整个页面设为'use client'
  • 如果存在RAM里,用户刷新页面Token就丢了,得重新调用刷新接口拿新的

虽然可以把Access Token也存成Cookie,但总觉得应该有更简便的方案,以下是我目前的实现代码:

"use server"

import { token } from "@/tokens"
import { cookies } from "next/headers"

export async function refreshToken() {
    const response: Response = await fetch(
        "http://localhost:8000/auth/refresh-token",
        {
            credentials: "include",
            method: "POST",
            headers: { Cookie: cookies().toString() },
        }
    )

    if (!response.ok) return

    const body = await response.json()

    if (!body.access_token) return

    token.token = body.access_token
}
export async function authFetch(url: string, init?: RequestInit): Promise<Response> {
    return await fetch(
        url,
        {
            headers: { "Authorization": `Bearer ${token.token}`, ...init?.headers },
            cache: "no-store"
        }
    )
}

推荐方案:服务器端自动处理Token刷新与携带

既然你不想用客户端存储、也不想依赖客户端组件,最简便的方式是让服务器端的请求工具自动完成Token刷新逻辑,彻底摆脱全局RAM存储的依赖:

  1. 重构authFetch,每次发起业务请求前,先通过Refresh Token获取有效Access Token,直接注入请求头:
"use server"

import { cookies } from "next/headers"

async function getValidAccessToken(): Promise<string | null> {
    // 调用刷新接口获取最新Access Token
    const response = await fetch("http://localhost:8000/auth/refresh-token", {
        credentials: "include",
        method: "POST",
        headers: { Cookie: cookies().toString() },
    })

    if (!response.ok) return null
    const body = await response.json()
    return body.access_token || null
}

export async function authFetch(url: string, init?: RequestInit): Promise<Response> {
    const accessToken = await getValidAccessToken()
    if (!accessToken) {
        // Token刷新失败,可返回401或触发登录跳转逻辑
        return new Response(null, { status: 401 })
    }

    return await fetch(url, {
        headers: { 
            "Authorization": `Bearer ${accessToken}`, 
            ...init?.headers 
        },
        cache: "no-store"
    })
}
  1. 移除全局token变量,所有业务请求统一通过authFetch发起——每次服务器端处理请求时,都会重新调用刷新接口获取有效Token,页面刷新后也不会出现Token丢失的问题。

方案优势

  • 全程无需客户端存储,也不用设置'use client',所有逻辑在服务器端完成
  • 页面刷新后,请求会自动重新获取Token,无状态丢失风险
  • 无需维护全局Token状态,减少代码复杂度

内容的提问来源于stack exchange,提问作者don dalladon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 20:36:13