Serverless Framework 如何从 AWS Cognito 获取访问令牌、身份令牌和刷新令牌

huangapple go评论63阅读模式
英文:

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: &#39;3&#39;
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: &quot;*&quot;
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: [&quot;email&quot;]
UserClient:
Type: AWS::Cognito::UserPoolClient
Properties:
ClientName: user-pool-ui
GenerateSecret: false
UserPoolId: { Ref: UserPool }
AccessTokenValidity: 1
IdTokenValidity: 1
ExplicitAuthFlows:
- &quot;ADMIN_NO_SRP_AUTH&quot;

<!-- 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 -->

&quot;token_use&quot;: &quot;id&quot;

<!-- 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(&#39;aws-sdk&#39;)
const { sendResponse, validateInput } = require(&quot;../functions&quot;);
const cognito = new AWS.CognitoIdentityServiceProvider()
module.exports.handler = async (event) =&gt; {
try {
const isValid = validateInput(event.body)
if (!isValid)
return sendResponse(400, { message: &#39;Invalid input&#39; })
const { email, password } = JSON.parse(event.body)
const { user_pool_id, client_id } = process.env
const params = {
AuthFlow: &quot;ADMIN_NO_SRP_AUTH&quot;,
UserPoolId: user_pool_id,
ClientId: client_id,
AuthParameters: {
USERNAME: email,
PASSWORD: password
}
}
const response = await cognito.adminInitiateAuth(params).promise();
return sendResponse(200, { 
message: &#39;Success&#39;,
accessToken: response.AuthenticationResult.AccessToken,
idToken: response.AuthenticationResult.IdToken ,
refreshToken: response.AuthenticationResult.RefreshToken ,
})
}
catch (error) {
const message = error.message ? error.message : &#39;Internal server error&#39;
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/

huangapple
  • 本文由 发表于 2023年2月19日 23:52:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/75501372.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定