如何在AWS Cognito用户池注册时获取身份提供商OAuth令牌?
获取AWS Cognito注册时的Google OAuth令牌(离线访问)
Hey there! I’ve tackled this exact scenario before—getting Google’s access_token and refresh_token for offline access when users sign up via AWS Cognito. Let’s walk through why your initial attempts didn’t work, and the actionable fixes to make this happen.
为什么你的前两种方案没拿到令牌?
- amazon-cognito-auth-js库:默认情况下,Cognito不会暴露第三方身份提供商的令牌,除非你显式配置属性映射并使用正确的OAuth流程。你之前看到的属性映射选项里没有令牌,是因为需要先创建自定义用户属性。
- Google JS API + Cognito创建用户:这个思路是对的,但你大概率漏掉了请求
offline_access权限(这是获取refresh令牌的关键),也没处理好联合登录后的令牌存储逻辑。
可行方案1:配置Cognito + amazon-cognito-auth-js获取令牌
这种方案完全依托Cognito生态,但需要仔细配置:
Step 1:准备Cognito用户池
- 创建自定义属性:进入你的Cognito用户池 → Attributes → Add custom attribute,创建
custom:google_access_token和custom:google_refresh_token(设置为可写)。 - 配置Google身份提供商:在用户池的Identity providers → Google页面,确保:
- 除了
openid、email、profile,还添加了offline_access权限。 - 在Attribute mapping里,将Google的
access_token映射到你的custom:google_access_token属性,refresh_token映射到custom:google_refresh_token。
- 除了
- 更新应用客户端:确保你的应用客户端使用Authorization Code Grant流程(而非implicit流程),且包含
offline_access权限。
Step 2:调整auth-js代码
使用授权码流程(获取refresh令牌必须),登录后获取映射的属性:
const authData = { ClientId: "YOUR_COGNITO_APP_CLIENT_ID", AppWebDomain: "YOUR_COGNITO_DOMAIN.auth.region.amazoncognito.com", TokenScopesArray: ["openid", "email", "profile", "offline_access"], RedirectUriSignIn: "YOUR_REDIRECT_URI", RedirectUriSignOut: "YOUR_LOGOUT_URI", ResponseType: "code" // 必须用code流程获取refresh令牌 }; const auth = new AmazonCognitoAuth(authData); auth.userhandler = { onSuccess: (result) => { // 获取用户属性(包括映射的Google令牌) const userPool = new AmazonCognitoIdentity.CognitoUserPool({ UserPoolId: "YOUR_COGNITO_USER_POOL_ID", ClientId: "YOUR_COGNITO_APP_CLIENT_ID" }); const cognitoUser = userPool.getCurrentUser(); cognitoUser.getUserAttributes((err, attributes) => { if (err) throw err; // 从自定义属性中提取Google令牌 const googleAccessToken = attributes.find(attr => attr.Name === "custom:google_access_token")?.Value; const googleRefreshToken = attributes.find(attr => attr.Name === "custom:google_refresh_token")?.Value; // 用这些令牌实现Google API的离线访问 console.log("Google Access Token:", googleAccessToken); console.log("Google Refresh Token:", googleRefreshToken); }); }, onFailure: (err) => console.error("登录失败:", err) }; auth.getSession();
可行方案2:Google JS API + Cognito联合登录(更灵活)
这种方法让你在将用户传递给Cognito之前直接控制Google的令牌,适合需要将令牌存储在自有数据库的场景。
Step 1:Google API配置
初始化Google Auth SDK时,务必启用offline_access权限:
gapi.load("auth2", () => { auth2 = gapi.auth2.init({ client_id: "YOUR_GOOGLE_CLIENT_ID", scope: "openid email profile offline_access" // 获取refresh令牌的关键 }); });
Step 2:处理Google登录 + Cognito注册
用户通过Google认证后,获取令牌并联合登录到Cognito:
async function signInWithGoogle() { try { const googleUser = await auth2.signIn({ prompt: "consent" }); // 强制授权,确保重复登录也能获取refresh令牌 const authResponse = googleUser.getAuthResponse(); // 直接获取Google令牌 const googleIdToken = authResponse.id_token; const googleAccessToken = authResponse.access_token; const googleRefreshToken = authResponse.refresh_token; // 仅首次授权时返回 // 联合登录到Cognito(新用户会自动创建) const userPool = new AmazonCognitoIdentity.CognitoUserPool({ UserPoolId: "YOUR_COGNITO_USER_POOL_ID", ClientId: "YOUR_COGNITO_APP_CLIENT_ID" }); userPool.federatedSignIn( "Google", googleIdToken, googleUser.getBasicProfile(), (err, result) => { if (err) throw err; // 可选:将令牌保存到Cognito自定义属性 const cognitoUser = result.user; const attributes = [ new AmazonCognitoIdentity.CognitoUserAttribute({ Name: "custom:google_access_token", Value: googleAccessToken }), new AmazonCognitoIdentity.CognitoUserAttribute({ Name: "custom:google_refresh_token", Value: googleRefreshToken || "" }) ]; cognitoUser.updateAttributes(attributes, (updateErr) => { if (updateErr) console.error("更新属性失败:", updateErr); else console.log("Google令牌已保存到Cognito"); }); } ); } catch (err) { console.error("Google + Cognito登录失败:", err); } }
关键注意事项
- Google Refresh令牌:Google仅在首次授权时返回refresh令牌。后续要获取新的refresh令牌,需要在Google登录调用中添加
prompt: "consent"(如上例所示)。 - Cognito属性限制:自定义属性有大小限制,确保你的令牌在限制范围内(Google令牌通常符合要求)。
- 安全性:务必安全存储refresh令牌——不要长期在客户端暴露。使用Cognito的安全存储或自有加密数据库。
内容的提问来源于stack exchange,提问作者Bill Johnston
相关产品推荐
相关产品推荐

