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

NextAuth V5如何获取JWT Token并用于Express鉴权

获取NextAuth自动生成的JWT Token用于后端鉴权

我知道NextAuth会自动生成JWT Token,但不清楚如何获取该Token,以便添加到请求头中调用后端需要鉴权的接口。以下是我的相关代码和问题:

1. NextAuth配置(auth.ts)

import NextAuth from "next-auth";
import Google from "next-auth/providers/google";
import Credentials from "next-auth/providers/credentials";
import axios from "axios";

export const { handlers, signIn, signOut, auth } = NextAuth({
  session: {
    strategy: "jwt",
    maxAge: 30 * 24 * 60 * 60,
  },
  providers: [
    Google({
      clientId: process.env.AUTH_GOOGLE_ID,
      clientSecret: process.env.AUTH_GOOGLE_SECRET,
    }),
    Credentials({
      name: "Credentials",
      credentials: {
        email: { label: "Email", type: "email" },
        password: { label: "Password", type: "password" },
      },
      authorize: async (credentials) => {
        try {
          const res = await axios.post('http://localhost:8080/api/auth/login', {
            email: credentials.email,
            password: credentials.password,
          });

          const user = res.data;
          
          if (user) {
            return user;
          } else {
            return null;
          }
        } catch (error) {
          console.error("Login error:", error);
          return null;
        }
      },
    }),
  ],
  callbacks: {
    async signIn({ user, account }) {
      if (account?.provider === 'google') {
        const res = await fetch('http://localhost:8080/api/auth/google-signin', {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
          },
          body: JSON.stringify({
            idToken: account.id_token, 
          }),
        });

        if (!res.ok) {
          console.error("Failed to create user");
          return false;
        }

        const userData = await res.json();
        if (userData && userData.role) {
          user.role = userData.role;
        }
      }
      return true;
    },
    async jwt({ token, user }) {
      return {...token, ...user};
    },
    async session({ session, token }) {
      session.user = token as any;
      return session;
    },
  },
  secret: process.env.AUTH_SECRET,
  pages: {
    signIn: "/login",
  },
});

2. 当前获取的Session对象

{
  "user": {
    "name": "testuser",
    "email": "testuser@test.com",
    "picture": "https://lh3.googleusercontent.com/a/ACg8ocJ-Cr0XVdUf5HfHhOvsVZuC3ShYaNPWv-cAjJTRs5mhoF91cw=s96-c",
    "sub": "66a8c9b102c0bd61a0a65639",
    "id": "66a8c9b102c0bd61a0a65639",
    "role": "user",
    "image": "https://lh3.googleusercontent.com/a/ACg8ocJ-Cr0XVdUf5HfHhOvsVZuC3ShYaNPWv-cAjJTRs5mhoF91cw=s96-c",
    "iat": 1722577679,
    "exp": 1725169679,
    "jti": "17493ea5-a58d-4a1c-ac3a-102039df7856"
  },
  "expires": "2024-09-01T05:48:00.555Z"
}

可以看到Session中没有直接提供Token字符串,无法直接添加到请求头。

3. 后端Express鉴权中间件

import * as jwt from "jsonwebtoken";
import { Request, Response, NextFunction } from "express";

const jwtSecretKey = process.env.AUTH_SECRET;

interface IIsAuth extends Request {
  userId?: string;
  userRole?: string;
}

const checkAuth = (req: IIsAuth, res: Response, next: NextFunction) => {
  try {
    const token = (req.headers.authorization || "").replace(/Bearer\s?/, "");
    const decodedToken = jwt.verify(token, jwtSecretKey) as { UserInfo: { _id: string, role: string }  };
    req.userId = decodedToken.UserInfo._id; 
    req.userRole = decodedToken.UserInfo.role; 
    next();
  } catch (error) {
    console.error("Error authenticating user:", error);
    res.status(403).json({ message: "Unauthorized" });
  }
};

export default checkAuth;

我希望能在Session中获取到Token,或者了解如何正确将Token添加到请求头中。我认为无需在后端单独生成JWT,因为NextAuth应该会自动处理。


解决方案

方案一:使用NextAuth生成的JWT对接后端鉴权

NextAuth生成的JWT默认不会暴露在Session中,但可以通过getToken方法获取原始Token字符串,同时需要调整JWT结构匹配后端鉴权逻辑:

  1. 调整NextAuth的JWT回调,匹配后端结构
    修改callbacks.jwt,构造后端期望的UserInfo字段:
async jwt({ token, user }) {
  if (user) {
    // 添加后端鉴权需要的UserInfo结构
    token.UserInfo = {
      _id: user.id,
      role: user.role
    };
  }
  return {...token, ...user};
}
  1. 获取JWT字符串
  • 服务器组件/API路由中直接获取:
import { auth, getToken } from '@/auth';

export default async function ServerComponent() {
  const session = await auth();
  // 获取NextAuth生成的原始JWT字符串
  const jwtToken = await getToken({ req });

  // 调用后端接口时携带Token
  const apiRes = await fetch('http://localhost:8080/api/protected', {
    headers: {
      Authorization: `Bearer ${jwtToken}`
    }
  });
}
  • 客户端组件中通过API路由中转:
    先创建一个API路由app/api/get-jwt/route.ts:
import { getToken } from 'next-auth/jwt';
import { NextResponse } from 'next/server';

export async function GET(req: Request) {
  const token = await getToken({ req, secret: process.env.AUTH_SECRET });
  return NextResponse.json({ token });
}

然后在客户端组件中调用该接口获取Token:

'use client';

import { useEffect, useState } from 'react';

export default function ClientComponent() {
  const [jwtToken, setJwtToken] = useState<string | null>(null);

  useEffect(() => {
    const fetchToken = async () => {
      const res = await fetch('/api/get-jwt');
      const data = await res.json();
      setJwtToken(data.token);
    };
    fetchToken();
  }, []);

  // 调用后端接口
  const callProtectedApi = async () => {
    if (!jwtToken) return;
    const res = await fetch('http://localhost:8080/api/protected', {
      headers: {
        Authorization: `Bearer ${jwtToken}`
      }
    });
  };

  return <button onClick={callProtectedApi}>调用保护接口</button>;
}

方案二:使用后端返回的Token(针对Credentials登录)

如果你的后端登录接口会返回自己的JWT,可以将其存入NextAuth的Session中:

  1. 在Credentials授权中保存后端Token
    修改authorize函数,将后端返回的Token添加到user对象:
authorize: async (credentials) => {
  try {
    const res = await axios.post('http://localhost:8080/api/auth/login', {
      email: credentials.email,
      password: credentials.password,
    });

    const user = res.data;
    // 假设后端返回的Token字段为token
    user.backendToken = res.data.token;
    
    if (user) {
      return user;
    } else {
      return null;
    }
  } catch (error) {
    console.error("Login error:", error);
    return null;
  }
},
  1. 将Token传递到Session
    通过jwt和session回调,将Token添加到Session中:
async jwt({ token, user }) {
  return {...token, ...user};
},
async session({ session, token }) {
  session.user = token as any;
  // 将后端Token添加到Session的user对象
  session.user.backendToken = token.backendToken;
  return session;
},
  1. 前端获取Token并使用
    从Session中取出backendToken,添加到请求头:
'use client';

import { useSession } from 'next-auth/react';

export default function ClientComponent() {
  const { data: session } = useSession();

  const callProtectedApi = async () => {
    if (!session?.user?.backendToken) return;
    const res = await fetch('http://localhost:8080/api/protected', {
      headers: {
        Authorization: `Bearer ${session.user.backendToken}`
      }
    });
  };

  return <button onClick={callProtectedApi}>调用保护接口</button>;
}

内容的提问来源于stack exchange,提问作者Tall Lorenc

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 02:15:56