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

Next-Auth集成AWS Cognito无法获取JWT access_token求助

问题

我在Next.js 13项目里用Next-Auth集成了AWS Cognito做认证,登录已经成功,也能通过useSession()拿到会话信息,但现在需要调用同一个Cognito保护的REST API,得把用户的Bearer令牌传给API才能获取专属数据,目前拿不到用于API认证的JWT令牌。

我的app/api/auth/[...nextauth]/route.js代码如下:

import NextAuth from "next-auth";
import CognitoProvider from "next-auth/providers/cognito";

export const authOptions = {
  providers: [
    CognitoProvider({
     clientId: process.env.COGNITO_CLIENT_ID,
     clientSecret: process.env.COGNITO_CLIENT_SECRET,
     issuer: process.env.COGNITO_ISSUER,
     authorization: {
       params: {
         scope: "openid",
       },
     },
}),
],
session: {
  jwt: true
},
secret: process.env.NEXTAUTH_SECRET,
jwt: {
 encryption: true,
},
callbacks: {
  async jwt({ token, user }) {
   return { ...token, ...user };
  },
  async session({ session, token, user }) {
   session.user = token;
   return session;
  },
 },
};

const handler = NextAuth(authOptions);

export { handler as GET, handler as POST };

调用useSession()打印会话信息到控制台时,完全看不到JWT令牌相关内容。

解决方案

1. 调整Cognito授权Scope

首先修改CognitoProvider的scope,确保能获取到Cognito颁发的id_token和access_token,把scope扩展为:

authorization: {
  params: {
    scope: "openid email profile", // 按需添加,至少保留openid,建议补充email、profile
  },
},

如果需要调用Cognito管理类API,还可以追加aws.cognito.signin.user.admin。

2. 修改JWT回调,保存Cognito令牌

原来的jwt回调只合并了token和user,但Cognito返回的核心令牌(id_token、access_token、refresh_token)实际在account参数里,需要把这些令牌存入token对象:

async jwt({ token, user, account }) {
  // 用户首次登录时,把Cognito令牌存入token
  if (user && account) {
    token.idToken = account.id_token;
    token.accessToken = account.access_token;
    token.refreshToken = account.refresh_token;
    token.expiresAt = account.expires_at * 1000; // 转成毫秒时间戳,方便后续判断过期
  }
  // 令牌未过期则返回现有token,过期可在此添加刷新逻辑
  if (Date.now() < token.expiresAt) {
    return token;
  }
  // 临时返回原token,可自行补充令牌刷新逻辑
  return token;
},

3. 修改Session回调,暴露令牌到前端

要让前端通过useSession()拿到令牌,需要在session回调里把令牌字段挂载到session对象上:

async session({ session, token }) {
  session.user.idToken = token.idToken;
  session.user.accessToken = token.accessToken;
  session.user.refreshToken = token.refreshToken;
  return session;
},

4. 处理JWT加密的影响

如果开启了jwt: { encryption: true },Next-Auth会对JWT加密,前端拿到的是加密后的内容,无法直接用作API的Bearer令牌。如果需要在前端直接使用Cognito令牌,建议关闭加密:

jwt: {
  encryption: false, // 关闭加密,前端才能拿到原始的Cognito令牌
},

如果必须保留加密,只能在Next.js的API路由中获取令牌,再转发给后端API(服务器端不受加密影响)。

修改后的完整代码

import NextAuth from "next-auth";
import CognitoProvider from "next-auth/providers/cognito";

export const authOptions = {
  providers: [
    CognitoProvider({
      clientId: process.env.COGNITO_CLIENT_ID,
      clientSecret: process.env.COGNITO_CLIENT_SECRET,
      issuer: process.env.COGNITO_ISSUER,
      authorization: {
        params: {
          scope: "openid email profile", // 扩展scope获取令牌和用户信息
        },
      },
    }),
  ],
  session: {
    jwt: true,
  },
  secret: process.env.NEXTAUTH_SECRET,
  jwt: {
    encryption: false, // 关闭加密以在前端获取原始令牌
  },
  callbacks: {
    async jwt({ token, user, account }) {
      if (user && account) {
        token.idToken = account.id_token;
        token.accessToken = account.access_token;
        token.refreshToken = account.refresh_token;
        token.expiresAt = account.expires_at * 1000;
      }
      if (Date.now() < token.expiresAt) {
        return token;
      }
      // 可选:添加令牌刷新逻辑
      return token;
    },
    async session({ session, token }) {
      session.user.idToken = token.idToken;
      session.user.accessToken = token.accessToken;
      session.user.refreshToken = token.refreshToken;
      return session;
    },
  },
};

const handler = NextAuth(authOptions);

export { handler as GET, handler as POST };

前端使用示例

现在在组件里调用useSession(),就能拿到session.user.accessToken,直接作为Bearer令牌传给API:

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

async function fetchUserInfo() {
  const { data: session } = useSession();
  if (!session) return;
  
  const res = await fetch("https://your-api-endpoint.com/user", {
    headers: {
      Authorization: `Bearer ${session.user.accessToken}`,
    },
  });
  const data = await res.json();
  console.log(data);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 23:53:25