個人開発レベルでBedrockを呼び出すチャットボットアプリを作成していたのですが、そのアプリに認証機能を作成したいなと思い立ったため、備忘録的にこの記事を残します。
チャットボット作成してみた件はこちらから。
ユーザプールの作成
認証のみ実施したいので、IDプールは使用しません。ユーザプールとIDプールの違いについては、以下を参照ください。
【Cognito】User PoolとIdentity Poolについて - Qiita
ユーザプールを作成していきます。
Reactで作成したSPAが、既にS3でホスティング済みのため、「シングルページアプリケーション(SPA)」を選択します。
また、「従来のウェブアプリケーション」と「シングルページアプリケーション」の違いはクライアントシークレットの有無に基づいているそうです。今回はクライアントシークレットを持たない「シングルページアプリケーション」を選択してます。
サインインオプションを選択していきます。
「リターンURL」は、CloudFrontのディストリビューションドメイン名を指定します。要はコールバックするURLのことです。
複数登録できるので、以下3つを登録してます。
アプリケーションのリソースを設定する画面に遷移しましたが、後でも設定できるので、ここではページ右下の「概要に移動」をクリックして飛ばします。

ユーザプールが完成したので、ログインページを表示してログインを試します(僕はマネジメントコンソール上で事前にユーザを作成してからログインしました)。

しかしながら、現段階だとCloudFrontのディストリビューションドメイン名を直接叩いてもコールバック先へとアクセスできてしまいます。
そこで、CloudFrontにアクセスするとCognitoの認証ページに遷移するように設定を追加していきます。
CloudFrontとCognitoの連携
連携には「cognito-at-edge」を使います。
このNode.jsパッケージは、CloudFrontディストリビューションへのリクエストを行うユーザーがCognitoユーザープールを使用して認証されているかどうかを確認するのに役立ちます。この確認は、リクエストに含まれるCookieを参照することで行われ、リクエスト元が認証されていない場合は、ユーザープールのログインページにリダイレクトされます。
上記URLに記載の通り、まずはパッケージのダウンロードをしていきます。
CloudShellを起動して、以下のコマンドを打ちます。
mkdir cognito-at-edge
cd cognito-at-edge
npm install cognito-at-edge
vi index.js
index.jsを新規作成し、以下の記載をします。
const { Authenticator } = require('cognito-at-edge');
const authenticator = new Authenticator({
// Replace these parameter values with those of your own environment
region: 'us-east-1', // user pool region
userPoolId: 'us-east-1_tyo1a1FHH', // user pool ID
userPoolAppId: '63gcbm2jmskokurt5ku9fhejc6', // user pool app client ID
userPoolDomain: 'domain.auth.us-east-1.amazoncognito.com', // user pool domain
});
exports.handler = async (request) => authenticator.handle(request);
記載が完了したら、zip化します。
zip -r9 cognito-at-edge.zip *
zipファイルをS3にアップロードしておきます。
aws s3 cp cognito-at-edge.zip s3://<S3バケット名>/cognito-at-edge.zip
Lambda@Edgeの作成
作成したパッケージをLambda@Edgeにアップロードしていきます。
注意点として、Lambda@Edgeの制限上、Lambda 関数は、米国東部 (バージニア北部) リージョンにある必要があります。
Lambda@Edge に対する制限 - Amazon CloudFront
以下のようにLambda関数を作成しました。
関数名:cognito-at-edge
ランタイム:Node.js 22.x
アーキテクチャ:x86_64
アクセス権権:AWSポリシーテンプレートから新しいロールを作成
アクセス権限については、ポリシーテンプレートの選択肢から以下を選択します。

関数が作成し終わったら、S3に格納しておいたzipファイルをLambda関数にアップロードします。

続いて、画面右上の「アクション」から「Lambda@Edgeへのデプロイ」をクリックします。

ディストリビューションには、対象となるCloudFrontを選択します。

CloudFront側のステータスも有効になったらテストしてみます。
CloudFrontディストリビューションのURLを直接叩くと、Cognitoのサインイン画面にリダイレクトされました。うまくいってます。

ログイン動作も問題なかったです。
503エラー発生
ある程度時間を置いてからまたテストすると503エラーが発生してしまいました。

同じ現象が発生している記事を見つけましたので、こちらを参照します。
ユーザー認証付きの静的サイトをCognito+CloudFront+Lambda@Edgeで構築する - Qiita
え、クライアントシークレットを設定するってことは、ユーザプールのアプリケーションタイプを「従来のウェブアプリケーション」で作成し直さないといけないのか(SPAだとクライアントシークレットは無いため)。
ついでに以下の記事を見つけまして、バグが発生していたとな。
ということで、まとめてindex.js を編集していきます。
cognito-at-edge は CookiePath を指定して使おう
const { Authenticator } = require('cognito-at-edge');
const authenticator = new Authenticator({
// Replace these parameter values with those of your own environment
region: 'us-east-1', // user pool region
userPoolId: 'us-east-1_tyo1a1FHH', // user pool ID
userPoolAppId: '63gcbm2jmskokurt5ku9fhejc6', // user pool app client ID
userPoolDomain: 'domain.auth.us-east-1.amazoncognito.com', // user pool domain
userPoolAppSecret: 'XXXXXX', // 追加
cookiePath: '/', // 追加
});
exports.handler = async (request) => authenticator.handle(request);
上記で503エラーも解決しました。
ずっと勘違いしていたかもだけど、Cognitoの「ログインページを表示」から取得できるURLからログインすると503エラーが起きて、CloudFrontディストリビューション名/index.html をブラウザで叩くとエラーが起きないという挙動(ログインしてなかったらログインページに遷移)。
つまり、「ページにアクセスするためのURL=コールバックするURL」ということをちゃんと認識して、テストする際のURLはCloudFrontディストリビューション名/index.html を貫いていれば、503エラーがそもそも出なかったんじゃないか。それはまた別の機会に実験したいと思います。







