如何在React+Firebase 9与Chrome扩展Manifest V3中实现Google登录?
在React + Firebase 9 + Manifest V3环境下实现Google登录(解决"bad client id"错误)
问题核心
你开发基于React和Firebase 9的Chrome扩展(Manifest V3)时,尝试通过chrome.identity实现Google登录,已完成Identity配置且能弹出登录窗口,但选择邮箱后触发OAuth2 request failed: Service responded with error: 'bad client id: {0}'错误。
错误原因分析
- Firebase凭证创建方式错误:你错误地将客户端ID作为
GoogleAuthProvider.credential()的第一个参数,该方法的正确参数是Google ID Token,而非客户端ID。 - 客户端ID未在Firebase授权:Chrome扩展的OAuth客户端ID未添加到Firebase的授权列表,导致Firebase无法验证该来源的token。
- Chrome Identity API使用不当:
chrome.identity.getAuthToken()获取的是Chrome生态的token,而非Firebase所需的Google ID Token。
解决方案步骤
1. 替换Chrome Identity API调用(获取正确的ID Token)
使用chrome.identity.launchWebAuthFlow()替代getAuthToken(),获取Firebase兼容的Google ID Token:
const getGoogleAuthCredential = () => { return new Promise((resolve, reject) => { if (typeof chrome !== 'undefined' && chrome.identity) { // 替换为你在Google Cloud Console中创建的Chrome扩展OAuth客户端ID const clientId = "你的扩展客户端ID.apps.googleusercontent.com"; const scopes = "openid email profile"; const redirectUri = chrome.identity.getRedirectURL(); // 生成随机nonce防止重放攻击 const nonce = Math.random().toString(36).substring(2, 15); chrome.identity.launchWebAuthFlow({ url: `https://accounts.google.com/o/oauth2/v2/auth?client_id=${clientId}&response_type=id_token&redirect_uri=${encodeURIComponent(redirectUri)}&scope=${encodeURIComponent(scopes)}&nonce=${nonce}`, interactive: true }, (responseUrl) => { if (chrome.runtime.lastError) { console.error(chrome.runtime.lastError); reject(chrome.runtime.lastError); return; } // 从回调URL中提取ID Token const urlParams = new URLSearchParams(responseUrl.split('#')[1]); const idToken = urlParams.get('id_token'); if (!idToken) { reject(new Error('未能获取ID Token')); return; } const credential = GoogleAuthProvider.credential(idToken); resolve(credential); }); } else { reject(new Error('需要在Chrome扩展环境中运行')); } }); };
2. 配置Firebase与Google Cloud授权
- Google Cloud Console:确保你的Chrome扩展OAuth客户端ID已启用
Google Identity API,并配置正确的重定向URI(即chrome.identity.getRedirectURL()返回的地址)。 - Firebase控制台:进入「Authentication」→「登录方法」→「Google」,将Chrome扩展的OAuth客户端ID添加到「已授权的客户端ID」列表中。
- Manifest.json配置:确保扩展的manifest包含正确的权限与OAuth配置:
{ "manifest_version": 3, "permissions": ["identity"], "oauth2": { "client_id": "你的扩展客户端ID.apps.googleusercontent.com", "scopes": ["openid", "email", "profile"] } }
3. 完整修正后的登录处理函数
import { GoogleAuthProvider, signInWithCredential, signInWithPopup } from 'firebase/auth'; import triggerMessage from '../../components/common/SnackBar'; import { auth } from '../../firebase/firebase-config'; const getGoogleAuthCredential = () => { return new Promise((resolve, reject) => { if (typeof chrome !== 'undefined' && chrome.identity) { const clientId = "你的扩展客户端ID.apps.googleusercontent.com"; const scopes = "openid email profile"; const redirectUri = chrome.identity.getRedirectURL(); const nonce = Math.random().toString(36).substring(2, 15); chrome.identity.launchWebAuthFlow({ url: `https://accounts.google.com/o/oauth2/v2/auth?client_id=${clientId}&response_type=id_token&redirect_uri=${encodeURIComponent(redirectUri)}&scope=${encodeURIComponent(scopes)}&nonce=${nonce}`, interactive: true }, (responseUrl) => { if (chrome.runtime.lastError) { console.error(chrome.runtime.lastError); reject(chrome.runtime.lastError); return; } const urlParams = new URLSearchParams(responseUrl.split('#')[1]); const idToken = urlParams.get('id_token'); if (!idToken) { reject(new Error('未能获取ID Token')); return; } const credential = GoogleAuthProvider.credential(idToken); resolve(credential); }); } else { reject(new Error('需要在Chrome扩展环境中运行')); } }); }; export const googleAuthHandler = async () => { try { let credential; if (window.location.origin.includes("chrome-extension")) { credential = await getGoogleAuthCredential(); } else { const provider = new GoogleAuthProvider(); await signInWithPopup(auth, provider); return; } const result = await signInWithCredential(auth, credential); return result.user; } catch (error) { console.error(error); triggerMessage("Google登录失败,请重试。", "error") return null; } };
关键注意事项
- 生成
nonce参数时需确保随机性,避免固定值导致安全风险。 - 验证Google Cloud Console中,Chrome扩展的OAuth客户端ID的重定向URI与
chrome.identity.getRedirectURL()一致。 - 确保Firebase项目的Google登录方法已启用。
内容的提问来源于stack exchange,提问作者Pratik Tiwari
相关产品推荐
相关产品推荐

