Amazon Cognito でカスタム認証フローを使ってパスワードなしで認証させてみた

2023.03.30

いわさです。

Amazon Cognito ユーザープールではいくつかの組み込み認証フローが用意されています。
基本的な認証は実現出来るものの、特定のユースケースの際に組み込み認証フローだと実現出来ない場合があります。

例えば、Cognito ユーザーはユーザー名とパスワードが必要で、パスワードなしのユーザーを作成することは出来ません。
しかし、パスワードを使わずに別の方法で認証したいシーンは無いでしょうか。

そういった場合にはカスタム認証フローを使うことが出来ます。
本日はこれを使ってパスワードなしで認証出来てしまうフローを作成してみました。

なお、カスタム認証は Cognito Hosted UI では利用出来ません。

アプリケーションクライアント作成

次のようにALLOW_CUSTOM_AUTHを認証フローに選択したアプリケーションクライアントを作成します。

カスタム認証の実体は、Lambda トリガーによる独自の認証フローです。
チャレンジ名などを指定することで何重ものチャレンジを要求したり、条件を追加したり複雑なフローも実現することが出来ます。

逆に、無条件で許可する Lambda 関数にしてしまえばユーザー名だけで認証してトークンが取得出来てしまいます。
ここでは次のような Lambda 関数を作成しました。

index.mjs

const handler = async (event) => {
    event.response.issueTokens = true;
    event.response.failAuthentication = false;
    return event;
};
export { handler }

なお、カスタム認証の詳細な作成方法は以下の公式ドキュメントを参考にしてください。

作成した Lambda 関数をユーザープールの Lambda トリガーとして指定します。

認証してみる

認証してみましょう。

% cat AllowCustomAuth.json                                                        
{
    "AuthFlow": "CUSTOM_AUTH",
    "AuthParameters": {
        "USERNAME": "iwasa.takahito+user3@example.com"
    },
    "ClientId": "39kueqksevnskc3mdn1rj32tql"
}
% aws cognito-idp initiate-auth --cli-input-json file://AllowCustomAuth.json      
{
    "ChallengeParameters": {
        "USERNAME": "c9c24f9a-29ae-4e01-b625-8925c93b3902"
    },
    "AuthenticationResult": {
        "AccessToken": "...",
        "ExpiresIn": 3600,
        "TokenType": "Bearer",
        "RefreshToken": "...",
        "IdToken": "..."
    }
}

なんと認証パラメータにユーザー名を指定するだけでトークンが取得出来ましたね。

標準の組み込みフローには影響はない

ちなみに、今回設定した Lambda トリガーはカスタム認証フローでのみ動作するものです。
一つのユーザープールで複数の認証フローを使えるようにする場合はよくあると思いますが、例えば今回でいうとユーザー名+パスワードの認証フローでは正しいパスワードが必要です。

間違ったパスワード

% cat AllowUserPasswordAuth.json                                                  
{
    "AuthFlow": "USER_PASSWORD_AUTH",
    "AuthParameters": {
        "USERNAME": "d7d7b76a-73a2-4618-a9c5-f167da428ddb",
        "PASSWORD": "hogehoge2"
    },
    "ClientId": "12l3vr51oq0ph351geeugh163l"
}
% aws cognito-idp initiate-auth --cli-input-json file://AllowUserPasswordAuth.json

An error occurred (NotAuthorizedException) when calling the InitiateAuth operation: Incorrect username or password.

正しいパスワード

% cat AllowUserPasswordAuth.json                                                  
{
    "AuthFlow": "USER_PASSWORD_AUTH",
    "AuthParameters": {
        "USERNAME": "d7d7b76a-73a2-4618-a9c5-f167da428ddb",
        "PASSWORD": "hogehoge"
    },
    "ClientId": "12l3vr51oq0ph351geeugh163l"
}
% aws cognito-idp initiate-auth --cli-input-json file://AllowUserPasswordAuth.json
{
    "ChallengeParameters": {},
    "AuthenticationResult": {
        "AccessToken": "...",
        "ExpiresIn": 3600,
        "TokenType": "Bearer",
        "RefreshToken": "...",
        "IdToken": "..."
    }
}

さいごに

本日は Amazon Cognito でカスタム認証フローを使ってパスワードなし認証を作ってみました。

最早認証と言っていいのかすら怪しいです。ユーザー名だけでトークンを取得させることが出来ました。

セキュリティ上の問題があるのでこのまま使用するケースは無いと思いますが、Cognito のカスタム認証の柔軟性を紹介したくて作ってみました。
例えばシークレットハッシュのみで認証させるとか、MFA を組み合わせるとか、独自の認証コードで検証するとか、様々な拡張が出来るのではないでしょうか。