Node.js Lambda获取Cognito Token调用接口返回401问题求助
我在Node.js Lambda函数中开发了从AWS获取Token的代码,成功获取Token后调用任意接口均返回401 Unauthorized。
通过JWT解码后,Lambda获取的Token内容如下:
{ "sub": "*****", "iss": "https://cognito-idp.us-east-1.amazonaws.com/us-east-*****", "client_id": "*****", "origin_jti": "*****", "event_id": "******", "token_use": "access", "scope": "aws.cognito.signin.user.admin", "auth_time": 1719906953, "exp": 1719910553, "iat": 1719906953, "jti": "*****", "username": "*****" }
而通过Postman获取的Token解码后内容如下:
{ "sub": "*****", "iss": "https://cognito-idp.us-east-1.amazonaws.com/us-east-*****", "version": 2, "client_id": "*****", "origin_jti": "*****", "token_use": "access", "scope": "aws.cognito.signin.user.admin phone openid mpfapi/fullaccess email", "auth_time": 1719917974, "exp": 1719921574, "iat": 1719917974, "jti": "*****", "username": "*****" }
Lambda代码获取的Token调用接口返回401,Postman获取的Token可正常使用。我的Node.js代码如下:
const getSecretHash = (username, clientId, clientSecret) => { return crypto.createHmac('SHA256', clientSecret) .update(username + clientId) .digest('base64'); }; const authenticateUser = async (username, password) => { const client = new CognitoIdentityProviderClient({ region: RYSEregion }); const secretHash = getSecretHash(username, poolData.ClientId, poolData.ClientSecret); const params = { AuthFlow: 'USER_PASSWORD_AUTH', AuthParameters: { 'USERNAME': username, 'PASSWORD': password, 'SECRET_HASH': secretHash }, ClientId: poolData.ClientId }; try { const command = new InitiateAuthCommand(params); const response = await client.send(command); return response.AuthenticationResult.IdToken; } catch (error) { console.error("Error: ", error); throw error; } };
Postman配置:
- 认证类型:OAuth 2.0
- 授权类型:Authorization code
我推测问题是Postman通过重定向触发Cognito托管UI认证,Lambda用的是另一种认证方式,导致Token权限范围不一致,但找不到Cognito中添加权限范围的配置。请问我遗漏了什么?
核心原因
Lambda代码使用的USER_PASSWORD_AUTH认证流默认仅返回包含aws.cognito.signin.user.admin基础权限的Token,而Postman采用的Authorization Code流会自动请求并返回Cognito客户端配置中已启用的所有授权范围,这是两者scope字段差异的直接原因,也是401错误的核心诱因。
解决步骤
1. 在InitiateAuth请求中指定所需Scope
修改Lambda代码的AuthParameters,添加SCOPE参数,明确声明需要的权限范围(匹配Postman中的scope内容):
const params = { AuthFlow: 'USER_PASSWORD_AUTH', AuthParameters: { 'USERNAME': username, 'PASSWORD': password, 'SECRET_HASH': secretHash, // 添加指定权限范围 'SCOPE': 'aws.cognito.signin.user.admin phone openid mpfapi/fullaccess email' }, ClientId: poolData.ClientId };
2. 确认Cognito客户端已启用对应Scope
登录AWS控制台,进入目标Cognito用户池:
- 找到对应的应用客户端,进入「应用客户端设置」页面
- 确保「已授权的OAuth范围」中勾选了你需要的
phone、openid、email以及自定义的mpfapi/fullaccess范围 - 确认「允许的OAuth流」中已启用
USER_PASSWORD_AUTH(若未开启需勾选)
3. 修正返回的Token类型
你的代码当前返回的是IdToken,但从JWT的token_use字段来看,接口需要的是AccessToken(用于调用受保护接口的凭证,IdToken主要用于身份信息识别),需修改返回值:
// 替换原返回语句,返回AccessToken而非IdToken return response.AuthenticationResult.AccessToken;
内容的提问来源于stack exchange,提问作者MOHAMED

