使用Gmail API获取Token遇invalid_grant错误:页面刷新后失败
问题分析与解决
核心原因
OAuth 2.0的authorization_code是一次性凭证,首次用它请求Token后就会立即失效。刷新页面后你仍复用同一个code发起请求,必然会返回invalid_grant错误。
解决方案
1. 存储并复用refresh_token
首次获取到包含refresh_token的响应后,将其存入本地存储(如localStorage)。后续刷新页面时,不再使用已失效的authorization code,而是通过refresh_token请求新的access_token。
修改后的代码示例:
// 页面加载时优先检查是否存在refresh_token const refreshToken = localStorage.getItem('gmail_refresh_token'); const client_id = 'clientid'; const client_secret = 'Clientsecret'; const tokenEndpoint = 'https://www.googleapis.com/oauth2/v4/token'; const redirectUri = 'http://localhost/12345/main'; const authScope = 'https://www.googleapis.com/auth/gmail.readonly'; // 替换为你需要的权限范围 // 用refresh_token获取新access_token function refreshAccessToken() { const requestBody = `grant_type=refresh_token&refresh_token=${refreshToken}&client_id=${client_id}&client_secret=${client_secret}`; fetch(tokenEndpoint, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: requestBody }) .then(res => res.json()) .then(data => { console.log('新access_token:', data.access_token); }) .catch(err => { console.error('刷新Token失败:', err); // 若refresh_token失效,重新引导用户授权 window.location.href = `https://accounts.google.com/o/oauth2/v2/auth?client_id=${client_id}&redirect_uri=${redirectUri}&response_type=code&scope=${authScope}&access_type=offline`; }); } // 用authorization_code首次获取Token function getTokenWithAuthCode(code) { const requestBody = `grant_type=authorization_code&code=${code}&redirect_uri=${redirectUri}&client_id=${client_id}&client_secret=${client_secret}`; fetch(tokenEndpoint, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: requestBody }) .then(res => res.json()) .then(data => { console.log('首次获取Token:', data); // 存储refresh_token到本地 if (data.refresh_token) localStorage.setItem('gmail_refresh_token', data.refresh_token); }) .catch(err => console.error('首次获取Token失败:', err)); } // 页面初始化逻辑 const code = new URLSearchParams(window.location.search).get('code'); if (refreshToken) { refreshAccessToken(); } else if (code) { getTokenWithAuthCode(code); } else { // 无任何凭证,引导用户授权(需加access_type=offline才能拿到refresh_token) window.location.href = `https://accounts.google.com/o/oauth2/v2/auth?client_id=${client_id}&redirect_uri=${redirectUri}&response_type=code&scope=${authScope}&access_type=offline`; }
2. 关键注意事项
- 授权URL必须携带
access_type=offline参数,否则Google不会返回refresh_token。 - 绝对不要在前端代码中暴露
client_secret:前端代码可被任意查看,会导致密钥泄露。建议将Token请求逻辑移至后端,前端仅与自有后端交互,避免直接接触client_secret。
内容的提问来源于stack exchange,提问作者12341413451354134
相关产品推荐
相关产品推荐

