🙈

HTTP APIでCognitoの認証をやってみた

2022/05/04に公開

RestAPIに比べ、低レイテンシ・低コストのHTTP APIを使用して、Cognitoによる認証を実装してみました。
認証のみで認可の方はやってないです。

https://zenn.dev/marumarumeruru/articles/2f66265422d370
の続きです。

実装

template.yamlを下記のように更新して、
UserPoolを作成し、そのUserPoolを利用してHTTP APIで認証を行うように設定しました
admin-initiate-authでトークンを発行できるようにするために、ADMIN_USER_PASSWORD_AUTHを許可しています。

template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
  sam-app

  Sample SAM Template for sam-app

model/blob/master/docs/globals.rst
Globals:
  Function:
    Timeout: 3

Parameters:
  StageName:
    Type: String
    Default: Prod

Resources:
  UserPool:
    Type: AWS::Cognito::UserPool
    Properties:
      UserPoolName: MyUserPool
      AdminCreateUserConfig:
        AllowAdminCreateUserOnly: false
      Policies:
        PasswordPolicy:
          MinimumLength: 6
          RequireLowercase: false
          RequireNumbers: false
          RequireSymbols: false
          RequireUppercase: false
  UserPoolClient:
    Type: AWS::Cognito::UserPoolClient
    Properties:
      ClientName: MyUserPoolClient
      GenerateSecret: false
      RefreshTokenValidity: 7
      ExplicitAuthFlows:
        - ALLOW_ADMIN_USER_PASSWORD_AUTH
        - ALLOW_CUSTOM_AUTH
        - ALLOW_USER_SRP_AUTH
        - ALLOW_REFRESH_TOKEN_AUTH
      UserPoolId:
        Ref: UserPool
  HttpApi:
    Type: AWS::Serverless::HttpApi
    Properties:
      Auth:
        Authorizers:
          MyAuthorizer:
            IdentitySource: $request.header.Authorization
            JwtConfiguration:
              audience:
                - !Ref UserPoolClient
              issuer: !Join
                      - ""
                      - - https://cognito-idp.
                        - !Sub ${AWS::Region}
                        - .amazonaws.com/
                        - !Ref UserPool
        DefaultAuthorizer: MyAuthorizer
      StageName: !Sub ${StageName}
      
  HelloWorldFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: hello_world/
      Handler: app.lambda_handler
      Runtime: python3.7
      Events:
        HelloWorld:
          Type: HttpApi
          Properties:
            ApiId: !Ref HttpApi
            Path: /hello
            Method: get

Outputs:
  UserPoolId:
    Value: !Ref UserPool
  UserPoolClientId:
    Value: !Ref UserPoolClient
  HttpApiUrl:
    Description: URL of your API endpoint
    Value: !Sub 'https://${HttpApi}.execute-api.${AWS::Region}.amazonaws.com/${StageName}/'

deploy

sam build
sam deploy
StageNameをdevにする場合
sam deploy --parameter-overrides "StageName=dev"

認証されていないとエラーになる

curl https://*******.execute-api.ap-northeast-1.amazonaws.com/Prod/hello
{"message":"Unauthorized"}

テストユーザーの作成

ユーザー作成 UNCONFIRMEDの状態で作成される
aws cognito-idp sign-up --client-id (UserPoolClientIdの値) --username user1 --password password
CONFIRMEDに更新
aws cognito-idp admin-confirm-sign-up --user-pool-id (UserPoolの値)  --username user1

トークンの取得

IdToken取得
aws cognito-idp admin-initiate-auth --user-pool-id (UserPoolの値)  --client-id (UserPoolClientIdの値) --auth-flow ADMIN_NO_SRP_AUTH --auth-parameters USERNAME=user1,PASSWORD=password

{
    "AuthenticationResult": {
        "ExpiresIn": 3600, 
        "IdToken": "xxxxxxxxxxx", 
        "RefreshToken": "yyyyyyyyyy", 
        "TokenType": "Bearer", 
        "AccessToken": "zzzzzzzzzz"
    }, 
    "ChallengeParameters": {}
}

トークンを利用して認証する

HeaderにAuthorizationをIdTokenの値で登録してアクセスすることで、アクセスできる

curl https://*******.execute-api.ap-northeast-1.amazonaws.com/Prod/hello -H "Authorization:(IDTokenの値)"
{"message": "hello world"}

Discussion