Cognito ↔ API Gateway ↔ Lambda ↔ DynamoDB


はじめに

前回のものにユーザ認証を足すために Cognito を Authorizer として使う。出来上がりはこんな感じ。User は Cognito で認証されて、APIをコールできるようになったり、自分でサインナップできるようになったりする。

だいたいこの記事の通りでよい

「プログラミングせずにCognitoで新規ユーザー登録&サインインを試してみる」 というわかりやすい記事があるので、この通り実行するのがよい。Cognitoの多くのサンプルはサンプルクライアントを書くところから始まるけど、この記事は AWS CLI を使って、アプリコードなしに基本的な設定方法や動作が理解できるのがよい

ということでやってみます

Cognitoのユーザープールを作る

  • Cognito で ユーザープールユーザープールを作成するデフォルトを確認する
  • いろんな設定項目あるけどほとんどデフォルトのままでいい。以下の二点だけちゃんとやっとけばいけるはず
    • アプリクライアントのところでクライアントシークレットを作成のチェックを外す。ここだけはユーザプールを作ってしまった後では、UIに出て来なくなり変更できない1
    • Cognito > ユーザープール > アプリクライアント > 認証フローの設定のところでは認証用の管理 API のユーザー名パスワード認証を有効にする (ALLOW_ADMIN_USER_PASSWORD_AUTH) にチェック)2

  • プールを作成したらこの二つが割り当てられるのでメモっておく
    • プール ID us-east-2_BLQx42sOb
    • アプリクライアント ID 6m2vpnxplvjpgm7sasgj1n1qe2

プールにユーザを追加

プールを作ったら、全般設定 > ユーザーとグループ でユーザをつくって、アカウントのステータスCONFIRMED にしておく

作ったユーザーでログイン

環境変数に必要なパラメターを入れておいて

export AWS_USER_POOL_ID=us-east-2_BLQx42sOb
export AWS_CLIENT_ID=6m2vpnxplvjpgm7sasgj1n1qe2
export [email protected]
export AWS_PASSWORD=aLoo4@ni8

ログインする

cognito-signin.sh
aws cognito-idp admin-initiate-auth \
  --user-pool-id ${AWS_USER_POOL_ID} \
  --client-id ${AWS_CLIENT_ID} \
  --auth-flow ADMIN_NO_SRP_AUTH \
  --auth-parameters "USERNAME=${AWS_USER_EMAIL},PASSWORD=${AWS_PASSWORD}"

トークンなどが帰ってくる


{
    "ChallengeParameters": {},
    "AuthenticationResult": {
        "AccessToken": "eyJraWQiOiJ2XC82ZVI2UEYraFwvSHR5cGFjYWV2a20ydHhHZWx0QUFObzBSUlVMZnpscDg9IiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiIzNzg4MzllMC05MDhhLTRhNmUtYjQxNy1jNWJlYTQ3OTNhNjYiLCJldmVudF9pZCI6ImU4ZjdjMDZhLWRkODctNDNhYS05NDFjLTY1N2ExNjZhYmIwMyIsInRva2VuX3VzZSI6ImFjY2VzcyIsInNjb3BlIjoiYXdzLmNvZ25pdG8uc2lnbmluLnVzZXIuYWRtaW4iLCJhdXRoX3RpbWUiOjE2MTA3NzM2NDUsImlzcyI6Imh0dHBzOlwvXC9jb2duaXRvLWlkcC51cy1lYXN0LTIuYW1hem9uYXdzLmNvbVwvdXMtZWFzdC0yX0FIUHczM3NPYSIsImV4cCI6MTYxMDc3NzI0NSwiaWF0IjoxNjEwNzczNjQ1LCJqdGkiOiJiNTQwNzZiYy0wYWJlLTQ5M2MtOWFlMC02Y2JmZDdiMTQ3ZTAiLCJjbGllbnRfaWQiOiI1bTN2cG5pcGx2anBnbjVzYXNnazduOXFlMzIsInVzZXJuYW1lIjoibmFydXNhbkBtYWMuY29tIn0.RX-3qdeyIFi8IbXSh6rYOtDbYB0rfJURANPXFCStxwMUkQSSIXD9qSCxc4mDLqeyGxdC6e_TxhYbFazpvEeAIiTIBm6_87nBlF29K4Biumwr20UWmqmFH1kHAGaCmTZYdyD1Xfvz6ZgwtCWX6AtU3slgDCt9OdTncm-Fg4IS9-YujLdc1oe3gx_lDtJUSbnR56MxrwWPm6QwMCmn_WBRI_kal-4KMdzwU14gZg-Cz8Wx-cg6WdM676MxDr5QNEyubJ3eZXHYgJ5Q9Z9qJmJMnAkavB1cy32JUNMpo4tpQ38Eql44NIzL_EWfeQv9BafOv5rQWSibFc01HdteVT5dhA",
        "ExpiresIn": 3600,
        "TokenType": "Bearer",
        "RefreshToken": "eyJjdHkiOiJKV1QiLCJlbmMiOiJBMjU2R0NNIiwiYWxnIjoiUlNBLU9BRVAifQ.L-_SZdGAXZRDchnGgZEp8X5iAlfdfV-Aw2NVNGJKZI3KxEVYmpXJdLpquyXig2GCUyOqZa0e2wQtPIoBsXgXQcnLrcnqtb7bC03zYe9btEKVmZ7q0kocHR1u-QHO7GmvpcWkNej9Rs_dvdLwT7LNulttAawOnExkS4Z6fT8eURqoFWxbNOix10xAaqLUwPNbeqRZshrb8ETw01udgtlwVrs2oRnSocQpwDpS15CCHmY-eAnvLJgcDleEIPu1Zre9TqgGR7c-C7zy33-q4br9e97dPY8ZfKQPmDyXVMT8IHSpfyDuGmQqALzX0uU0oIJgOWu1rqTSrjMQnqwYJZnFkQ.lbkKN9Q63DQHc1wu.IiPOQmWpYdz04-Rk4loU3t1BftGUGd-iBJczhroII65IKfqthjdG8UpHvyifHa7pF8R_zKrx7W6rq1laP_fUP1bjsGq5eM46cl84OZTiCBtY9GLoU1V2fTvbjvh927liNwGqi1Vpw7IQSs3ElPn6BGtTIpvdSoSdBKnFCDL7UDUssGKynvVpigmWdgojJUl5WkSdJOrY4hm6HdDLg09BDtcEeKoAOAPQtK5st-2RWHfkqHNwAvGlcgibncDjXEQzKBmk6jv7K4G1XEKpeI3bkV24ptaeWnpZh_H9nuUd07OywIR4d1KOkuw7CH4cAQVeKQqrzPXaMJ2tLhlICo1iQtypCsVoY1J3oLVKu9aVakikqNIZUvv3sfbGbzjTYZBF9t5Iu3jUwaBbR-oUUh06E6fYultffQAoS3vk8odU78uHbju8FveamPZ2O_ofqK1TE8f0h2O9hH6i3bIU7QNbpDOd94YxzZgjkds8ShMEvNOmHrjd24j92wOK9iDe28JnXYeUoq5yx3lqMMhQ_pB9GHgV7MQ7N0w56UsuOkKbjYHvujoRRlJPNckS2fSwCd_wQafpuSu92frAe05rM8s2DIT2jW0SWptfAb9K_GF3_cOoDhtXAh2fsL2VDCvH6qv-bZ0ZpAtopxTqk9Gi8dQ_5oAj60sZ-hPY7cYRr1Of1YqxP0UmAxpprLDHax-iSFsBgiDtFjttxQjx1p3AqVjx0-tKdIzZZl3S20DAGsg0ODKJsVFhfRg7NG_5JjVd0_fcfVsrBmehZ3zc8Rzw7c7S2_4ashC-mTWOAzVFyRsaqIrMwCU86jHKf-OT19UzIdlJC29zRvS_odnVQEBqYs81uD_4Fandu6srGjaTsOTYE1edZMrgSQ03Qr8HbL0k52etRigyqqMKi9H0KU484e5cmQkdwf5dOELpNY-3Cs8gZ-HgUcWsUHifMRXxyYxrTp34X2LqbeIUYZ1iZCNkT7w-geOn4P6V5yitqKqZK07TES0IGB5WSwot2KtonE-wcZcKVXAbX8XcUKwBP_EUpr5ND_a0CZEq2IovF1eRCToEJe0dQ5MMS310GaI9LOlo7B_VUfdyHG396bjNvl2QN65YYHFizwpXZki2zWwwJUaAc94QBVvFimmVgueRcSMLWjSAkFYo-MjWHY-AiK_kxwLcK72psMWTLZSU-uh98suMW9-3PdUl49T5IjM3ArYvfcQlSX7wk_Hb4uuQI0NeH33wljebuUxVlkvZtRguaa_1TASn6zFh3Es4h7Ko9Eqm5e3QC40f6W-QJvipD3h5b3tN.n2fLFIqe70ozbeYl_gNN2g",
        "IdToken": "eyJraWQiOiJXSDdXTlloaDBFUFwvRm01VFJoNms0Y3VDUUxjbHgrSlNDSGN2RWM5Qml2VT0iLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiIzNzg4MzllMC05MDhhLTRhNmUtYjQxNy1jNWJlYTQ3OTNhNjYiLCJhdWQiOxI1bTN2cG5pcGx2anBnbjVzYXNnazduOXFlMyIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJldmVudF9pZCI6ImU4ZjdjMDZhLWRkODctNDNhYS05NDFjLTY1N2ExNjZhYmIwMyIsInRva2VuX3VzZSI6ImlkIiwiYXV0aF90aW1lIjoxNjEwNzczNjQ1LCJpc3MiOiJodHRwczpcL1wvY39nbml0by1pZHAudXMtZWFzdC0yLmFtYXpvbmF3cy5jb21cL3VzLWVhc3QtMl9BSFB3MzNzT2EiLCJjb2duaXRvOnVzZXJuYW1lIjoibmFydXNhbkBtYWMuY29tIiwiZXhwIjoxNjEwNzc3MjQ1LCJpYXQiOjE2MTA3NzM2NDUsImVtYWlsIjoibmFydXNhbkBtYWMuY29tIn0.s3Dfkiinhfxog0LheQXfX7jVEHUJGcC7b-8XwAegqnGcYTbt9EsJW9HJtW3q1owjBiMkPXKwJ1_hEjg2iTwYnqu1EYXEzWtgOj8n4X1iM2TYO-9ra1zmfvbJ7X3uTC8F4msPfLklqGDq34UXAY_vf-E0VbPyxBXllTzi2FY-3oFiAyxkGA1n8KqJ7AhobtxMnSOSjHoni78q_uxExZJ2PxZ0ruSg-hsKwfKlN6Pf593WHpeSC2RK_gnCr3qhzC1lRbv9_hUWbALXqMl3vowMLz9k4IV_oC9BU07LLIExR7wmI2_ZmTa6ts8TDATolcIDXNK-cBtsHn97aBul747XgQ"
    }
}

必要なのは、トークンのところだけなのでクエリで

TOKEN=$(aws cognito-idp admin-initiate-auth \
  --user-pool-id ${AWS_USER_POOL_ID} \
  --client-id ${AWS_CLIENT_ID} \
  --auth-flow ADMIN_NO_SRP_AUTH \
  --auth-parameters "USERNAME=${AWS_USER_EMAIL},PASSWORD=${AWS_PASSWORD}" \
  --query "AuthenticationResult.IdToken" | sed "s/\"//g") && echo ${ID_TOKEN}

これで$TOKENでトークンが取れるようになった

API GatewayからCognito認証する

API Gatewayのオーソライザーで、上で作ったユーザープールを指定する

APIのデプロイを忘れずに実行

テストしてみる

先の通り、$TOKEN にトークンを入れておいてAPIのエンドポイント叩きます

curl -H "Authorization: $TOKEN"  https://<api-id>.execute-api.us-east-2.amazonaws.com/dev_1/projects | jq
curl -X POST -d '{"project-id": 200, "name": "Typing", "is-default": false}' -H "Authorization: $TOKEN"  https://<api-id>.execute-api.us-east-2.amazonaws.com/dev_1/projects | jq
curl -X DELETE -d '{"project-id": 200}' -H "Authorization: $TOKEN"  https://<api-id>.execute-api.us-east-2.amazonaws.com/dev_1/projects | jq
curl -X PUT -d '{"project-id": 200, "name": "Yoga"}' -H "Authorization: $TOKEN"  https://<api-id>.execute-api.us-east-2.amazonaws.com/dev_1/projects | jq

動きました!

次回予告

CLI では動いたので、いよいよ次回はフロントエンドのクライアントをかいてみようか

シリーズ


  1. これやらないと CLI でユーザーをサインアップする時に An error occurred (NotAuthorizedException) when calling the SignUp operation: Unable to verify secret hash for client <CLIENT_ID> と怒られる 

  2. これやらないと CLI でサインインしようとしたときに An error occurred (InvalidParameterException) when calling the AdminInitiateAuth operation: Auth flow not enabled for this client