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

Firebase集成Discord OpenID/OAuth2认证遇错求助

解决Firebase与Discord OAuth2集成的认证错误

错误原因分析

1. OIDC Provider方式的auth/invalid-credential错误

Firebase的OpenID Connect Provider要求身份提供者返回标准OIDC格式的id_token(JWT类型,包含iss、sub等必填声明),但Discord的OAuth2服务并未实现完整的OIDC规范,不会返回符合要求的id_token,仅提供access_token,导致Firebase无法验证凭证有效性,触发该错误。

2. signInWithCustomToken的auth/internal-error错误

signInWithCustomToken方法仅接受Firebase Admin SDK生成的自定义令牌,而非第三方服务(如Discord)的access_token。直接传入Discord的access_token不符合Firebase的令牌格式要求,因此触发内部错误。

正确集成方案:自定义OAuth2流程

通过前端发起Discord授权、后端交换令牌并生成Firebase自定义令牌的方式实现集成,步骤如下:

1. 配置Discord OAuth2应用

  • 在Discord开发者平台的OAuth2设置中,添加前端回调页面的重定向URL(如https://your-domain.com/auth/callback)
  • 勾选所需权限范围(scope):identify、email(可根据业务需求扩展)

2. 前端发起Discord授权请求

构造授权URL并通过弹窗或重定向跳转:

const discordClientId = "YOUR_DISCORD_CLIENT_ID";
const redirectUri = "https://your-domain.com/auth/callback";
const scope = "identify email";
const state = crypto.randomUUID(); // 生成随机state防范CSRF攻击

// 存储state到localStorage用于后续验证
localStorage.setItem("discord_auth_state", state);

// 跳转至Discord授权页
window.location.href = `https://discord.com/api/oauth2/authorize?client_id=${discordClientId}&redirect_uri=${encodeURIComponent(redirectUri)}&response_type=code&scope=${encodeURIComponent(scope)}&state=${state}`;

3. 后端交换令牌并生成Firebase自定义令牌

注意:此步骤必须在后端执行,避免泄露Discord的client_secret

以Node.js为例:

const admin = require("firebase-admin");
const axios = require("axios");

// 初始化Firebase Admin SDK(提前配置好服务账号密钥)
admin.initializeApp({
  credential: admin.credential.cert("path/to/serviceAccountKey.json")
});

// 交换Discord授权码获取用户信息
async function exchangeDiscordCode(code) {
  const tokenResponse = await axios.post(
    "https://discord.com/api/oauth2/token",
    new URLSearchParams({
      client_id: "YOUR_DISCORD_CLIENT_ID",
      client_secret: "YOUR_DISCORD_CLIENT_SECRET",
      grant_type: "authorization_code",
      code: code,
      redirect_uri: "https://your-domain.com/auth/callback"
    }),
    { headers: { "Content-Type": "application/x-www-form-urlencoded" } }
  );

  // 获取Discord用户信息
  const userResponse = await axios.get("https://discord.com/api/users/@me", {
    headers: { Authorization: `Bearer ${tokenResponse.data.access_token}` }
  });

  return userResponse.data;
}

// 生成Firebase自定义令牌
async function generateFirebaseToken(discordUser) {
  // 用Discord用户ID作为Firebase UID(可自定义关联逻辑)
  const uid = `discord:${discordUser.id}`;
  // 添加自定义用户声明(可选)
  const additionalClaims = {
    email: discordUser.email,
    displayName: `${discordUser.username}#${discordUser.discriminator}`,
    avatar: discordUser.avatar
  };

  return admin.auth().createCustomToken(uid, additionalClaims);
}

// 示例接口:接收前端传来的授权码,返回Firebase自定义令牌
app.get("/auth/discord/callback", async (req, res) => {
  const { code, state } = req.query;
  const storedState = localStorage.getItem("discord_auth_state");

  // 验证state防止CSRF攻击
  if (state !== storedState) {
    return res.status(403).send("Invalid state parameter");
  }

  try {
    const discordUser = await exchangeDiscordCode(code);
    const customToken = await generateFirebaseToken(discordUser);
    res.json({ customToken });
  } catch (error) {
    res.status(500).send("Authentication failed");
  }
});

4. 前端使用自定义令牌登录Firebase

在回调页面中,获取后端返回的自定义令牌并完成登录:

// 从URL中提取授权码
const urlParams = new URLSearchParams(window.location.search);
const code = urlParams.get("code");

// 向后端请求Firebase自定义令牌
fetch(`/auth/discord/callback?code=${code}`)
  .then(res => res.json())
  .then(({ customToken }) => {
    // 登录Firebase
    return firebase.auth().signInWithCustomToken(customToken);
  })
  .then((userCredential) => {
    // 登录成功,处理用户信息
    const user = userCredential.user;
    console.log("登录成功", user);
    // 跳转到应用首页
    window.location.href = "/";
  })
  .catch(error => {
    console.error("登录失败", error);
  });

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 13:07:51