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

Next-Auth Credentials认证实现:对接已返回JWT令牌的Rails API

Next-Auth CredentialsProvider 对接外部返回JWT的接口配置方案

问题根源

你当前拿到的session_token并非Rails返回的JWT,是Next-Auth默认生成机制导致的:

  1. authorize 方法返回的用户对象只会在首次触发jwt回调时作为入参传入,不会自动写入Next-Auth生成的JWT载荷
  2. Next-Auth默认生成JWT时仅会自动添加签发时间iat、过期时间exp两个字段,自定义的token内容会被默认丢弃
  3. 你看到的30天有效期是Next-Auth的默认配置,和Rails返回的JWT有效期无关

配置说明

你不需要在authorize里重新组装令牌,只需要额外配置jwt和session两个回调,把Rails返回的JWT及相关信息同步到Next-Auth的会话体系中即可。是否需要解码Rails返回的JWT完全看你的使用需求:

  • 如果你只需要透传JWT调用Rails接口,直接存原始JWT字符串即可
  • 如果你需要在前端/Next.js服务端直接使用用户ID、角色等信息,可以提前解码后存入JWT载荷,避免后续重复解码

依赖安装(如需解码JWT)

如果需要解析Rails返回的JWT内容,推荐使用适配Edge环境的jose库:

npm install jose

完整[...nextauth].js配置

import NextAuth from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials";
import { decodeJwt } from "jose"; // 不需要解码可删除该行

export default NextAuth({
  // 明确指定session使用JWT策略,CredentialsProvider默认也会采用该策略
  session: {
    strategy: "jwt",
  },
  providers: [
    CredentialsProvider({
      name: 'Email',
      credentials: {
        email: { label: "Email", type: "email", placeholder: "meine.email@domain.com" },
        password: {  label: "Passwort", type: "password" }
      },
      async authorize(credentials) {
        const url = `${process.env.NEXT_PUBLIC_API_URL}/auth/login`;
        const res = await fetch(url, {
          method: 'POST',
          body: JSON.stringify(credentials),
          headers: {
            "Content-Type": "application/json" 
          }
        })
        const user = await res.json()
        if (res.ok && user?.token) {
          // 不需要解码可直接返回 { rawToken: user.token }
          const decodedToken = decodeJwt(user.token);
          return {
            rawToken: user.token,
            userId: decodedToken.user_id,
            roles: decodedToken.roles,
            exp: decodedToken.exp,
          };
        }
        return null
      }
    })
    // 后续要接入Twitter等第三方Provider直接在该数组中添加即可
  ],
  callbacks: {
    // JWT回调:把自定义信息存入Next-Auth的JWT载荷
    async jwt({ token, user }) {
      // 仅首次登录/授权时user参数有值,后续刷新JWT时仅传入token参数
      if (user) {
        token.rawToken = user.rawToken;
        token.userId = user.userId; // 不需要解码可删除该行
        token.roles = user.roles; // 不需要解码可删除该行
        token.exp = user.exp; // 同步Rails JWT的过期时间,不需要可删除该行使用默认30天有效期
      }
      return token;
    },
    // Session回调:把JWT里的信息同步到session对象,供前端useSession调用
    async session({ session, token }) {
      session.rawToken = token.rawToken;
      session.user.id = token.userId; // 不需要解码可删除该行
      session.user.roles = token.roles; // 不需要解码可删除该行
      return session;
    }
  }
})

前端使用方式

后续调用Rails接口时,直接从useSession中取rawToken放到请求头即可:

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

const { data: session } = useSession();
// 发起请求时添加授权头
const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/xxx`, {
  headers: {
    Authorization: `Bearer ${session.rawToken}`
  }
})

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 19:27:04