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

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

Serverless Framework How to Get Access, Id and Refresh Tokens from AWS Cognito

问题

我正在尝试使用AWS Cognito用户池来保护我的无服务器NodeJS API。

以下是我的无服务器框架配置的示例:

  1. service: hello-world
  2. frameworkVersion: '3'
  3. provider:
  4. name: aws
  5. runtime: nodejs14.x
  6. environment:
  7. user_pool_id: { Ref: UserPool }
  8. client_id: { Ref: UserClient }
  9. iam:
  10. role:
  11. statements:
  12. - Effect: Allow
  13. Action:
  14. - cognito-idp:AdminInitiateAuth
  15. - cognito-idp:AdminCreateUser
  16. - cognito-idp:AdminSetUserPassword
  17. Resource: "*"
  18. functions:
  19. loginUser:
  20. handler: ./auth/login.handler
  21. events:
  22. - http:
  23. path: auth/login
  24. method: post
  25. cors: true
  26. signupUser:
  27. handler: ./auth/signup.handler
  28. events:
  29. - http:
  30. path: auth/signup
  31. method: post
  32. cors: true
  33. list:
  34. handler: ./users/users.handler
  35. events:
  36. - http:
  37. path: users/list
  38. method: get
  39. cors: true
  40. authorizer:
  41. type: COGNITO_USER_POOLS
  42. authorizerId:
  43. Ref: ApiGatewayAuthorizer
  44. resources:
  45. Resources:
  46. ApiGatewayAuthorizer:
  47. Type: AWS::ApiGateway::Authorizer
  48. Properties:
  49. Name: CognitoUserPool
  50. Type: COGNITO_USER_POOLS
  51. IdentitySource: method.request.header.Authorization
  52. RestApiId:
  53. Ref: ApiGatewayRestApi
  54. ProviderARNs:
  55. - Fn::GetAtt:
  56. - UserPool
  57. - Arn
  58. UserPool:
  59. Type: AWS::Cognito::UserPool
  60. Properties:
  61. UserPoolName: serverless-auth-pool
  62. Schema:
  63. - Name: email
  64. Required: true
  65. Mutable: true
  66. Policies:
  67. PasswordPolicy:
  68. MinimumLength: 6
  69. AutoVerifiedAttributes: ["email"]
  70. UserClient:
  71. Type: AWS::Cognito::UserPoolClient
  72. Properties:
  73. ClientName: user-pool-ui
  74. GenerateSecret: false
  75. UserPoolId: { Ref: UserPool }
  76. AccessTokenValidity: 1
  77. IdTokenValidity: 1
  78. ExplicitAuthFlows:
  79. - "ADMIN_NO_SRP_AUTH"

我可以成功调用注册和登录端点以获取令牌,然后使用此令牌作为授权标头来调用我的/users/list端点以获取用户列表。

我的问题是,我原本期望登录端点返回3个令牌 - ID令牌、访问令牌和刷新令牌。

登录端点当前只返回一个具有以下声明的令牌:

  1. "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 -->

  1. service: hello-world
  2. frameworkVersion: &#39;3&#39;
  3. provider:
  4. name: aws
  5. runtime: nodejs14.x
  6. environment:
  7. user_pool_id: { Ref: UserPool }
  8. client_id: { Ref: UserClient }
  9. iam:
  10. role:
  11. statements:
  12. - Effect: Allow
  13. Action:
  14. - cognito-idp:AdminInitiateAuth
  15. - cognito-idp:AdminCreateUser
  16. - cognito-idp:AdminSetUserPassword
  17. Resource: &quot;*&quot;
  18. functions:
  19. loginUser:
  20. handler: ./auth/login.handler
  21. events:
  22. - http:
  23. path: auth/login
  24. method: post
  25. cors: true
  26. signupUser:
  27. handler: ./auth/signup.handler
  28. events:
  29. - http:
  30. path: auth/signup
  31. method: post
  32. cors: true
  33. list:
  34. handler: ./users/users.handler
  35. events:
  36. - http:
  37. path: users/list
  38. method: get
  39. cors: true
  40. authorizer:
  41. type: COGNITO_USER_POOLS
  42. authorizerId:
  43. Ref: ApiGatewayAuthorizer
  44. resources:
  45. Resources:
  46. ApiGatewayAuthorizer:
  47. Type: AWS::ApiGateway::Authorizer
  48. Properties:
  49. Name: CognitoUserPool
  50. Type: COGNITO_USER_POOLS
  51. IdentitySource: method.request.header.Authorization
  52. RestApiId:
  53. Ref: ApiGatewayRestApi
  54. ProviderARNs:
  55. - Fn::GetAtt:
  56. - UserPool
  57. - Arn
  58. UserPool:
  59. Type: AWS::Cognito::UserPool
  60. Properties:
  61. UserPoolName: serverless-auth-pool
  62. Schema:
  63. - Name: email
  64. Required: true
  65. Mutable: true
  66. Policies:
  67. PasswordPolicy:
  68. MinimumLength: 6
  69. AutoVerifiedAttributes: [&quot;email&quot;]
  70. UserClient:
  71. Type: AWS::Cognito::UserPoolClient
  72. Properties:
  73. ClientName: user-pool-ui
  74. GenerateSecret: false
  75. UserPoolId: { Ref: UserPool }
  76. AccessTokenValidity: 1
  77. IdTokenValidity: 1
  78. ExplicitAuthFlows:
  79. - &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 -->

  1. &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个令牌:

  1. const AWS = require('aws-sdk')
  2. const { sendResponse, validateInput } = require("../functions");
  3. const cognito = new AWS.CognitoIdentityServiceProvider()
  4. module.exports.handler = async (event) => {
  5. try {
  6. const isValid = validateInput(event.body)
  7. if (!isValid)
  8. return sendResponse(400, { message: 'Invalid input' })
  9. const { email, password } = JSON.parse(event.body)
  10. const { user_pool_id, client_id } = process.env
  11. const params = {
  12. AuthFlow: "ADMIN_NO_SRP_AUTH",
  13. UserPoolId: user_pool_id,
  14. ClientId: client_id,
  15. AuthParameters: {
  16. USERNAME: email,
  17. PASSWORD: password
  18. }
  19. }
  20. const response = await cognito.adminInitiateAuth(params).promise();
  21. return sendResponse(200, {
  22. message: 'Success',
  23. accessToken: response.AuthenticationResult.AccessToken,
  24. idToken: response.AuthenticationResult.IdToken ,
  25. refreshToken: response.AuthenticationResult.RefreshToken ,
  26. })
  27. }
  28. catch (error) {
  29. const message = error.message ? error.message : 'Internal server error';
  30. return sendResponse(500, { message });
  31. }
  32. }

注意:我还必须向授权程序添加了scopes,以使API接受访问令牌:

  1. list:
  2. handler: ./users/users.handler
  3. events:
  4. - http:
  5. path: users/list
  6. method: get
  7. cors: true
  8. authorizer:
  9. type: COGNITO_USER_POOLS
  10. scopes:
  11. - aws.cognito.signin.user.admin
  12. authorizerId:
  13. 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 -->

  1. const AWS = require(&#39;aws-sdk&#39;)
  2. const { sendResponse, validateInput } = require(&quot;../functions&quot;);
  3. const cognito = new AWS.CognitoIdentityServiceProvider()
  4. module.exports.handler = async (event) =&gt; {
  5. try {
  6. const isValid = validateInput(event.body)
  7. if (!isValid)
  8. return sendResponse(400, { message: &#39;Invalid input&#39; })
  9. const { email, password } = JSON.parse(event.body)
  10. const { user_pool_id, client_id } = process.env
  11. const params = {
  12. AuthFlow: &quot;ADMIN_NO_SRP_AUTH&quot;,
  13. UserPoolId: user_pool_id,
  14. ClientId: client_id,
  15. AuthParameters: {
  16. USERNAME: email,
  17. PASSWORD: password
  18. }
  19. }
  20. const response = await cognito.adminInitiateAuth(params).promise();
  21. return sendResponse(200, {
  22. message: &#39;Success&#39;,
  23. accessToken: response.AuthenticationResult.AccessToken,
  24. idToken: response.AuthenticationResult.IdToken ,
  25. refreshToken: response.AuthenticationResult.RefreshToken ,
  26. })
  27. }
  28. catch (error) {
  29. const message = error.message ? error.message : &#39;Internal server error&#39;
  30. return sendResponse(500, { message })
  31. }
  32. }

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

  1. list:
  2. handler: ./users/users.handler
  3. events:
  4. - http:
  5. path: users/list
  6. method: get
  7. cors: true
  8. authorizer:
  9. type: COGNITO_USER_POOLS
  10. scopes:
  11. - aws.cognito.signin.user.admin
  12. authorizerId:
  13. 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:

确定