英文:
Serverless Framework How to Get Access, Id and Refresh Tokens from AWS Cognito
问题
我正在尝试使用AWS Cognito用户池来保护我的无服务器NodeJS API。
以下是我的无服务器框架配置的示例:
service: hello-world
frameworkVersion: '3'
provider:
name: aws
runtime: nodejs14.x
environment:
user_pool_id: { Ref: UserPool }
client_id: { Ref: UserClient }
iam:
role:
statements:
- Effect: Allow
Action:
- cognito-idp:AdminInitiateAuth
- cognito-idp:AdminCreateUser
- cognito-idp:AdminSetUserPassword
Resource: "*"
functions:
loginUser:
handler: ./auth/login.handler
events:
- http:
path: auth/login
method: post
cors: true
signupUser:
handler: ./auth/signup.handler
events:
- http:
path: auth/signup
method: post
cors: true
list:
handler: ./users/users.handler
events:
- http:
path: users/list
method: get
cors: true
authorizer:
type: COGNITO_USER_POOLS
authorizerId:
Ref: ApiGatewayAuthorizer
resources:
Resources:
ApiGatewayAuthorizer:
Type: AWS::ApiGateway::Authorizer
Properties:
Name: CognitoUserPool
Type: COGNITO_USER_POOLS
IdentitySource: method.request.header.Authorization
RestApiId:
Ref: ApiGatewayRestApi
ProviderARNs:
- Fn::GetAtt:
- UserPool
- Arn
UserPool:
Type: AWS::Cognito::UserPool
Properties:
UserPoolName: serverless-auth-pool
Schema:
- Name: email
Required: true
Mutable: true
Policies:
PasswordPolicy:
MinimumLength: 6
AutoVerifiedAttributes: ["email"]
UserClient:
Type: AWS::Cognito::UserPoolClient
Properties:
ClientName: user-pool-ui
GenerateSecret: false
UserPoolId: { Ref: UserPool }
AccessTokenValidity: 1
IdTokenValidity: 1
ExplicitAuthFlows:
- "ADMIN_NO_SRP_AUTH"
我可以成功调用注册和登录端点以获取令牌,然后使用此令牌作为授权标头来调用我的/users/list
端点以获取用户列表。
我的问题是,我原本期望登录端点返回3个令牌 - ID令牌、访问令牌和刷新令牌。
登录端点当前只返回一个具有以下声明的令牌:
"token_use": "id"
如果我将此令牌传递给/users/list
API,它将成功验证,但我以为 API 需要访问令牌而不是 ID 令牌进行身份验证。
有谁知道我的假设是否正确,如何解决问题,还是我是否误解了认证流程?
英文:
I am trying to secure my serverless NodeJS apis using AWS Cognito User Pools.
Below is a sample of my serverless framework configuration:
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
service: hello-world
frameworkVersion: '3'
provider:
name: aws
runtime: nodejs14.x
environment:
user_pool_id: { Ref: UserPool }
client_id: { Ref: UserClient }
iam:
role:
statements:
- Effect: Allow
Action:
- cognito-idp:AdminInitiateAuth
- cognito-idp:AdminCreateUser
- cognito-idp:AdminSetUserPassword
Resource: "*"
functions:
loginUser:
handler: ./auth/login.handler
events:
- http:
path: auth/login
method: post
cors: true
signupUser:
handler: ./auth/signup.handler
events:
- http:
path: auth/signup
method: post
cors: true
list:
handler: ./users/users.handler
events:
- http:
path: users/list
method: get
cors: true
authorizer:
type: COGNITO_USER_POOLS
authorizerId:
Ref: ApiGatewayAuthorizer
resources:
Resources:
ApiGatewayAuthorizer:
Type: AWS::ApiGateway::Authorizer
Properties:
Name: CognitoUserPool
Type: COGNITO_USER_POOLS
IdentitySource: method.request.header.Authorization
RestApiId:
Ref: ApiGatewayRestApi
ProviderARNs:
- Fn::GetAtt:
- UserPool
- Arn
UserPool:
Type: AWS::Cognito::UserPool
Properties:
UserPoolName: serverless-auth-pool
Schema:
- Name: email
Required: true
Mutable: true
Policies:
PasswordPolicy:
MinimumLength: 6
AutoVerifiedAttributes: ["email"]
UserClient:
Type: AWS::Cognito::UserPoolClient
Properties:
ClientName: user-pool-ui
GenerateSecret: false
UserPoolId: { Ref: UserPool }
AccessTokenValidity: 1
IdTokenValidity: 1
ExplicitAuthFlows:
- "ADMIN_NO_SRP_AUTH"
<!-- end snippet -->
I can successfully can call the signup and login endpoints to get a token and then use this token as an Authorization header to call my /users/list
endpoint to get a list of users.
My problem is that I was expecting the login endpoint to return 3 tokens - an id token, an access token and a refresh token.
The login endpoint currently only returns one token that has a claim of:
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
"token_use": "id"
<!-- end snippet -->
If I pass this token to the /users/list
api then it is successfully validated, but I thought that the api would need the access token instead of the id token for authentication.
Does anyone know if my assumption is correct and how to fix the issue or have I misunderstood how the auth flow works ?
答案1
得分: 0
我设法弄清楚我的登录函数只返回了id令牌。以下是更新后的登录函数,用于返回所有3个令牌:
const AWS = require('aws-sdk')
const { sendResponse, validateInput } = require("../functions");
const cognito = new AWS.CognitoIdentityServiceProvider()
module.exports.handler = async (event) => {
try {
const isValid = validateInput(event.body)
if (!isValid)
return sendResponse(400, { message: 'Invalid input' })
const { email, password } = JSON.parse(event.body)
const { user_pool_id, client_id } = process.env
const params = {
AuthFlow: "ADMIN_NO_SRP_AUTH",
UserPoolId: user_pool_id,
ClientId: client_id,
AuthParameters: {
USERNAME: email,
PASSWORD: password
}
}
const response = await cognito.adminInitiateAuth(params).promise();
return sendResponse(200, {
message: 'Success',
accessToken: response.AuthenticationResult.AccessToken,
idToken: response.AuthenticationResult.IdToken ,
refreshToken: response.AuthenticationResult.RefreshToken ,
})
}
catch (error) {
const message = error.message ? error.message : 'Internal server error';
return sendResponse(500, { message });
}
}
注意:我还必须向授权程序添加了scopes
,以使API接受访问令牌:
list:
handler: ./users/users.handler
events:
- http:
path: users/list
method: get
cors: true
authorizer:
type: COGNITO_USER_POOLS
scopes:
- aws.cognito.signin.user.admin
authorizerId:
Ref: ApiGatewayAuthorizer
我正在使用的完整注册/登录流程基于以下freeCodeCamp示例:
https://www.freecodecamp.org/news/aws-cognito-authentication-with-serverless-and-nodejs/
英文:
I managed to figure out that my login function was only returning the id token. Below is the updated login function to return all 3 tokens:
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
const AWS = require('aws-sdk')
const { sendResponse, validateInput } = require("../functions");
const cognito = new AWS.CognitoIdentityServiceProvider()
module.exports.handler = async (event) => {
try {
const isValid = validateInput(event.body)
if (!isValid)
return sendResponse(400, { message: 'Invalid input' })
const { email, password } = JSON.parse(event.body)
const { user_pool_id, client_id } = process.env
const params = {
AuthFlow: "ADMIN_NO_SRP_AUTH",
UserPoolId: user_pool_id,
ClientId: client_id,
AuthParameters: {
USERNAME: email,
PASSWORD: password
}
}
const response = await cognito.adminInitiateAuth(params).promise();
return sendResponse(200, {
message: 'Success',
accessToken: response.AuthenticationResult.AccessToken,
idToken: response.AuthenticationResult.IdToken ,
refreshToken: response.AuthenticationResult.RefreshToken ,
})
}
catch (error) {
const message = error.message ? error.message : 'Internal server error'
return sendResponse(500, { message })
}
}
<!-- end snippet -->
Note: I also had to add scopes
to the authorizer to be make the api accept the access token
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
list:
handler: ./users/users.handler
events:
- http:
path: users/list
method: get
cors: true
authorizer:
type: COGNITO_USER_POOLS
scopes:
- aws.cognito.signin.user.admin
authorizerId:
Ref: ApiGatewayAuthorizer
<!-- end snippet -->
The full signup/login flow that I am using is based on the following free code camp example:
https://www.freecodecamp.org/news/aws-cognito-authentication-with-serverless-and-nodejs/
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论