はじめに

WEBサイトのログイン画面を作る際、idやパスワード以外にカスタム項目を使用してユーザのログインの管理をしたい場合この記事を参考にすることができます。今回紹介するのはCognitoのUSER_PASSWORD_AUTH を使用し、IDトークンなどの認証情報を取得する前にトリガー関数を起動させることで、IDトークンにカスタム項目を追加し認証情報を返却する方法です。

https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/cognito-idp.html

事前準備

  • Cognito ユーザープールの作成(USER_PASSWORD_AUTH ができる設定)
  • テストユーザの作成

以下の状態であれば問題ありません。

 

initiate_authを行うLambda関数の作成

Lambda関数を使用してユーザ認証を行います。Python 3.12を使用してコンソールから関数を作成します。

import json
import boto3


def lambda_handler(event, context):
    client = boto3.client('cognito-idp')
    auth_infos = client.initiate_auth(
        ClientId='ユーザープールのクライアントID',
        AuthFlow='USER_PASSWORD_AUTH',
        AuthParameters={
            'USERNAME': event.get('user'),
            'PASSWORD': event.get('password')
        }
    )
    return {
        'statusCode': 200,
        'body': json.dumps({
            'AccessToken': auth_infos['AuthenticationResult']['AccessToken'],
            'ExpiresIn': auth_infos['AuthenticationResult']['ExpiresIn'],
            'TokenType': auth_infos['AuthenticationResult']['TokenType'],
            'RefreshToken': auth_infos['AuthenticationResult']['RefreshToken'],
            'IdToken': auth_infos['AuthenticationResult']['IdToken']
        })
    }

以下のようにユーザプールに登録したidとパスワードを渡してLambda関数を実行します。

{
  "user": "test_user_01",
  "password": "IretTest1!"
}

結果は以下のようになりました。

{
  "statusCode": 200,
  "body": "{\"AccessToken\": \"eyJraWQiOiJyR3BqdktFYllmbzRrZE03YThNTUY2aHpOZ0pvWjdpWmZaTENtTmJyREtBPSIsImFsZyI6IlJTMjU2In0.eyJzdWIiOiJkMmMzMTk5Zi03ZTJmLTQ0ODUtODBhOC03ODZkZWQwYjVlNGUiLCJpc3MiOiJodHRwczpcL1wvY29nbml0by1pZHAuYXAtc291dGhlYXN0LTIuYW1hem9uYXdzLmNvbVwvYXAtc291dGhlYXN0LTJfdlBHcnYwQlo0IiwiY2xpZW50X2lkIjoiMjQ0czliZWxlb2Q5bXJub3RoNmdrN2c1OGsiLCJvcmlnaW5fanRpIjoiMjFiMGJhMDItNjZkNi00ZGFmLTgyYzktYmRjNjkyMzBkNWNkIiwiZXZlbnRfaWQiOiI2NmQ3ZDc5Zi0yNWQ4LTQ2MGMtOGQ3MC0yZTk4YzU0Yjc1ZWMiLCJ0b2tlbl91c2UiOiJhY2Nlc3MiLCJzY29wZSI6ImF3cy5jb2duaXRvLnNpZ25pbi51c2VyLmFkbWluIiwiYXV0aF90aW1lIjoxNzA3ODEwODQyLCJleHAiOjE3MDc4MTQ0NDIsImlhdCI6MTcwNzgxMDg0MiwianRpIjoiZjA4MDBiNTEtOTc1My00YTBhLTkzYWQtNjkzZmM2OGQwYjVhIiwidXNlcm5hbWUiOiJ0ZXN0X3VzZXJfMDEifQ.c8aDqsaOUkwwNhOKx3EIFKQs5y1_Elkm8lmsefOfoDdWUfBkyAbOI5q7t3_GKG3f57tHEMqZpFnGdUSAIUGruG2-7md9Nhf5JcQftKJazzwV4FW7MLJJDzDxZs3V1Sq7qMWtUFuK0BGUG26q5nYGodkewFgYYi2L39BxFV0Vv_p94c5-ORWQQHyPL2tov8e6Ag-qKFVwVlI-WR8cJA_VD832csocH3N8CNjSS-c9zGWYMYEVw63ASc4W1wIpxbVVqrkb4AXLEyGMW3NDdlezCgJLeIpMmyRsRCwU6oOS_TehrvIHB7beskMjuZKTgpqVouwcMEZSfb4ju6fkHXL3ww\", \"ExpiresIn\": 3600, \"TokenType\": \"Bearer\", \"RefreshToken\": \"eyJjdHkiOiJKV1QiLCJlbmMiOiJBMjU2R0NNIiwiYWxnIjoiUlNBLU9BRVAifQ.h9UDi2x2mbFii3kb_O4dIgRJJD1IX0cXFUK98RqVChm7mE0Js3Gjj9_24fHZJ2MJSwceUUOmQP2yZQ13-pUczg_lWXJkH40S9qyDvBr5Da2ZQkWkoTgTpfGdpnhijQ7AK3MdJynFu0e51mOAfg14CfyWIZv8SuVSin8LkCUx4tmMixDVrr6XnhrbdzzoX4Ag6gaSrCQq111ExULnRx7zbCtelWRZm7glMl9nph-VBOP081xTqox0Ee6Em1eNzSwxQL4AEZ7duTWBQ1b54Rhz5NiWiuekdrBz-oav_c236_0eQ7e2gsBpdHaEg1brRKW-0HOmmI2MS45DJTiL59xbJA.l0k5dM4rPu3OjO3Y.Om0reB499hV4PzeE3bIzdb2aNTomxv-VbHlIWrlLlM7DPzs4M1i0sQ5PbJebT46vnhQnIfSuSts3UZZvvfRTv7P6sX6G1Lg-XBhBgnh9fbIBgGHNd6S8SYsf_bYZGh4B7v5rknjcZEMpC9ElbgWfWFY1XtzzlBnlo6q0AGliw6adWNDjyIKYO_U-CeqH45vv_64f087G4cAec1WaKQA9_h53JFEyqn0h8DKPjNWUsxg_KnyomRsgGxNt1nOeu_v0BfX4D_fJeu1JeDjTRtaNdbqX8gU66mkAtNdOosb9LXCZ0aPGj0WJWBLvh_5KHeSrn-2Xp86HbNW-5_OIDEQ5oSrzfXCh8a9Vc7RcVuwVIXq6ieMHQygF41zBzE2JESAeTvGWQgBVC27okecFJ14vAIse5E_x49afBBV0ChySdfyzrh6vSrZcsoYBnsuYioXbV4mASqKZ-xNke5tFup5IWbB6n4vYx-3sjYyAkJICfwuhUZyGI7wbLMHSMByc-QffsJIkKlJIDyfsVUXikE6WmUd8GzPIUWIFgV56soll4Pj7Vi4eVuaWobN2b-8EG-DV-mz0IDbvhWaOGDGfPvlmDLpIH7tM0PcORk2OW9yctZV8okc8BnHyS4oN_QILjQBHgf-B0RoLTz5jF_5-4CNBpHQQh2LbtG-A8APdN_iAwtcvOZ6G9xPQKqWuPoGVtLjyHUPyT6WLXwpCWKGYULk8DE2qjM0Phvm9RZe3ay5P4TERz9r9SsmD85hpeiZkjYh2ox48-fdsI-Kpeay_ZNiEfzxqeOOsESZQJnHfY5W8ak9E8qNDvbZy9hivpFr0USI0R34gPAAmebUI7Sqgg7YamOwa1YvVXGZVOw3AlTiNKWX18jaYhARjUAljQzPDJYMsWm2NxdMfjKen_ollB-WHAnxJK2A6m8mlqhDIC_cNsdtFS0F29PYCJAi-XxDDe_F_Hxq4JUZWm_iePvsKVghn-EsXcQ_vGI4wj77Wi8XNjLEKoLknr5sHO-mIGkg-kZrj9PfR9jq_Q2TzcrNX7BJrUv84YPyYBSer3fFWejIgkgXKmd_ZVkO0cTbCU5aWmMIokj4Ozd7tzx9_BsvihtCN6iA3rCZCzH9mF-YRGJEaKRUfueJLxm9fkSCsNzJ8eE74PCDH11DsXdL6mS_JbZD1uSZofvJz7A9dJOVLBxqmltwkkUxtl7C9JIENVoMYHDplhhLkw3_jPu5M_5iYmKJYdK8VaVqmi0k2ROcN5gDH_ImeRqm-sEP3PcpFcgERrPn52TzHi2SteGpCRAO6SlM4oL-r2DeCzRKYew.mZ-BR5-2B3EFbDP3haZ6aQ\", \"IdToken\": \"eyJraWQiOiJBclwvUjh4SlVLSVl5WkJacUx2WGpPaGpVRW1SaUl6RVwvVHJlb240NnorMlE9IiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiJkMmMzMTk5Zi03ZTJmLTQ0ODUtODBhOC03ODZkZWQwYjVlNGUiLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiaXNzIjoiaHR0cHM6XC9cL2NvZ25pdG8taWRwLmFwLXNvdXRoZWFzdC0yLmFtYXpvbmF3cy5jb21cL2FwLXNvdXRoZWFzdC0yX3ZQR3J2MEJaNCIsImNvZ25pdG86dXNlcm5hbWUiOiJ0ZXN0X3VzZXJfMDEiLCJvcmlnaW5fanRpIjoiMjFiMGJhMDItNjZkNi00ZGFmLTgyYzktYmRjNjkyMzBkNWNkIiwiYXVkIjoiMjQ0czliZWxlb2Q5bXJub3RoNmdrN2c1OGsiLCJldmVudF9pZCI6IjY2ZDdkNzlmLTI1ZDgtNDYwYy04ZDcwLTJlOThjNTRiNzVlYyIsInRva2VuX3VzZSI6ImlkIiwiYXV0aF90aW1lIjoxNzA3ODEwODQyLCJleHAiOjE3MDc4MTQ0NDIsImlhdCI6MTcwNzgxMDg0MiwianRpIjoiN2Y2YWJiOWUtNDI2OS00OGM5LThkNjEtMzFkZjQ1MTg3NGM1IiwiZW1haWwiOiJ5b3NoaWRhQGlyZXQuY28uanAifQ.oVhLR_FdaaJqfDqMdP5kPyeQuZcLiSaokG7YW7IigRuxC5UWLWhalfwMLW7ayFtEqr8vbpqKl3jIKOijWjiKMNzaOQMWTuHqXD16ZQBPR9Lqi4Eqj72NDxTWSR8z684NhbSt2BwEjAMldSAr9lyxLR3qt1fO_OsfnxeP71LVmgQUjlEfOzKVLxLs-NjGmzsnh3G3eZ85USuf0jgrC43OnuTEonpzQaZslly7cET0W2USo0SmxbAJVy8Kk0qRSgzSW7Z3CcUaW-h94zV3a0WMm0y51qZio1GUhgty2QyWMAnqrjvQDIRx8xWGnWWjSJOHST3I2TJAciVvVkDwVYV-OA\"}"
}

次にIdTokenの内容を確認します。返却されたIdTokenのJWTを解析すると以下のようになります。

{
  "sub": "d2c3199f-7e2f-4485-80a8-786ded0b5e4e",
  "iss": "XXX",
  "client_id": "XXX",
  "origin_jti": "ea8a7355-2dad-490a-a179-a5ff867c632d",
  "event_id": "81cb863a-1aa8-4ea2-a42d-0b4ae104fa54",
  "token_use": "access",
  "scope": "aws.cognito.signin.user.admin",
  "auth_time": 1707810242,
  "exp": 1707813842,
  "iat": 1707810242,
  "jti": "6e7efee7-33ab-499c-b22c-2d4bc63b7f27",
  "username": "test_user_01"
}

認証に成功し、usernameが取得できていることがわかります。

トークン生成前トリガーの作成

トークン生成前に起動するLambda関数を作成して、IdTokenに任意の項目を追加します。任意の項目を追加する方法としては、作成したトリガー関数のevent.response.claimsOverrideDetails.claimsToAddOrOverrideに任意の項目を追加しeventを返却するだけです。

def lambda_handler(event, context):
    code_list = {
        'test_user_01': '0001',
        'test_user_02': '0002'
    }
    event['response']['claimsOverrideDetails'] = {
        'claimsToAddOrOverride': {
            'iret_code': code_list[event.get('userName')]
        }
    }
    return event

ユーザプールにトークン生成前トリガーを追加

Cognitoコンソールからユーザプールを選択し、トークン生成前トリガーを追加してLambda関数を割り当てます。

ユーザープールのプロパティを選択し、Lambdaトリガーを追加から認証を選択します。トークン生成前トリガーを選択し作成したトリガーを割り当てます。

以下のように追加されていれば問題ないです。

initiate_authを行いIdTokenの内容を確認

最初に作成した関数を起動しトークンの内容を確認します。

{
  "sub": "d2c3199f-7e2f-4485-80a8-786ded0b5e4e",
  "email_verified": true,
  "iss": "XXX",
  "cognito:username": "test_user_01",
  "origin_jti": "7cf44d49-7408-4583-9fde-e83307778c48",
  "aud": "244s9beleod9mrnoth6gk7g58k",
  "event_id": "ffff20f8-981e-4bc9-91dd-fbb1a0dbf738",
  "token_use": "id",
  "auth_time": 1707822452,
  "iret_code": "0001",
  "exp": 1707826051,
  "iat": 1707822452,
  "jti": "0f644579-b8de-425e-b144-f4b785ff92f4",
  "email": "test@iret.co.jp"
}

内容を確認すると最初に実行した時と比べ内容が変化していることがわかります。トリガーの関数で追加したiret_codeというものが追加されるようになっています。

まとめ

この記事では、トークン生成前トリガーを使用することで簡単にカスタム項目を含める方法を解説しました。

トリガー関数の中でusernameを取得し、DBなどを参照してユーザに対する追加情報を認証情報に追加します。その後、一つ目に作成した認証を行う関数内で、フロントから受け取ったパラメータとIDToken内のカスタム項目を比較することでログイン自体のカスタム項目を簡単に増やすことができます。