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

Next Auth集成Firebase Auth:如何存储获取Bearer令牌用于API请求

实现Firebase idToken的存储与API请求携带

步骤1:修改Next Auth的authorize函数,获取并返回Firebase idToken

在authorize方法中调用Firebase的getIdToken()获取令牌,将其与用户邮箱一起返回:

async authorize(credentials, req) {
  try {
    const userCredential = await signInWithEmailAndPassword(
      auth,
      credentials.email,
      credentials.password
    );
    // 获取Firebase的idToken(异步方法)
    const idToken = await userCredential.user.getIdToken();
    
    if (userCredential.user) {
      return { 
        email: userCredential.user.email,
        idToken: idToken
      };
    } 
    return null;
  } catch (error) {
    throw new Error('Invalid email or password');
  }
}

步骤2:配置Next Auth的会话策略与回调,注入idToken到会话

Credentials Provider仅支持JWT会话策略,显式配置后通过jwt和session回调将idToken存入会话:

export default NextAuth({
  secret: process.env.NEXTAUTH_SECRET,
  pages: {
    signIn: '/auth/signin',
  },
  // 配置会话为JWT策略
  session: {
    strategy: "jwt",
  },
  providers: [/* 原CredentialsProvider代码 */],
  callbacks: {
    // 将idToken存入JWT令牌
    async jwt({ token, user }) {
      // 登录时,user是authorize返回的对象
      if (user) {
        token.idToken = user.idToken;
        token.email = user.email;
        // 记录令牌生成时间和过期时间(Firebase令牌有效期1小时)
        token.iat = Math.floor(Date.now() / 1000);
        token.exp = token.iat + 3600;
      }
      return token;
    },
    // 将idToken从JWT提取到前端可用的session对象
    async session({ session, token }) {
      session.user.idToken = token.idToken;
      session.user.email = token.email;
      return session;
    },
  },
});

步骤3:前端获取idToken并在API请求中携带

使用Next Auth的useSession钩子获取会话中的idToken,发起请求时添加到Authorization头:

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

function DataFetchComponent() {
  const { data: session } = useSession();

  const fetchProtectedData = async () => {
    if (!session?.user?.idToken) {
      alert("请先登录");
      return;
    }

    const response = await fetch("/api/protected", {
      method: "GET",
      headers: {
        Authorization: `Bearer ${session.user.idToken}`,
      },
    });

    if (!response.ok) {
      console.error("请求失败");
      return;
    }

    const data = await response.json();
    console.log("获取到的数据:", data);
  };

  return (
    <button onClick={fetchProtectedData}>获取受保护数据</button>
  );
}

export default DataFetchComponent;

步骤4:(可选)自动刷新过期的idToken

Firebase idToken有效期为1小时,在jwt回调中添加逻辑自动刷新:

async jwt({ token, user }) {
  if (user) {
    token.idToken = user.idToken;
    token.email = user.email;
    token.iat = Math.floor(Date.now() / 1000);
    token.exp = token.iat + 3600;
  }

  // 当前时间离过期还有5分钟以上,无需刷新
  const now = Math.floor(Date.now() / 1000);
  if (token.exp - now > 300) {
    return token;
  }

  // 强制刷新令牌
  try {
    const currentUser = auth.currentUser;
    if (currentUser) {
      const newIdToken = await currentUser.getIdToken(true);
      return {
        ...token,
        idToken: newIdToken,
        iat: Math.floor(Date.now() / 1000),
        exp: Math.floor(Date.now() / 1000) + 3600,
      };
    }
    return token;
  } catch (error) {
    console.error("刷新idToken失败:", error);
    return token;
  }
}

步骤5:后端API验证idToken(可选)

如果需要在后端验证令牌有效性,使用Firebase Admin SDK:

// /api/protected/route.js
import { adminAuth } from "@/util/firebase-admin"; // 提前初始化Firebase Admin

export async function GET(req) {
  const authHeader = req.headers.get("Authorization");
  if (!authHeader || !authHeader.startsWith("Bearer ")) {
    return new Response(JSON.stringify({ error: "未授权" }), { status: 401 });
  }

  const idToken = authHeader.split(" ")[1];
  try {
    // 验证并解码idToken
    const decodedToken = await adminAuth.verifyIdToken(idToken);
    return new Response(
      JSON.stringify({ message: "请求成功", user: decodedToken }),
      { status: 200 }
    );
  } catch (error) {
    return new Response(JSON.stringify({ error: "无效令牌" }), { status: 401 });
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 07:44:57