はじめてのCognito
最近になってはじめてCognitoを使う機会があったので、調べたことをまとめました。
Cognitoとは
Cognitoは認証やユーザー管理の仕組みを提供するAWSのサービスです。詳しくはドキュメントです。
調べていてつまずいたこと
振り返るとそんなに難しいことではない気もしますが、初見だと以下のようなことに疑問を持ちました。
Cognitoを調べるとAmplifyとセットになって紹介してる記事がたくさんあり、Amplifyとは?AmplifyとCognitoってどういう関係?
- Amplifyは、アプリケーションを作るために必要なサービス群(たとえばホスティングや認証やストレージ、バックエンドのAPIなど)をいい感じにまとめて提供してくれるAWSの仕組みです。その仕組みの中で、認証だとCognitoが使われているので、Cognitoを調べるとAmplifyの情報もたくさん出てきた感じでした。Amplifyと合わせてCognitoを使った場合も、Cognito単独で使った場合も、Cognito自体の認証の仕組みは変わらないです。
ユーザープールとは?対応してるユースケース多そうだけど、今回はどのケースに当てはまる?などのCognito自体の知識
- ユーザープールは、ユーザーを管理する仕組みです。ユーザー登録したり、ログインするときに使います。
- 基本はやはりドキュメントですが、概要を理解するにあたって、図が多くてこの資料がわかりやすかったです。
フロントからCognitoのリソースを操作したいときに、使うライブラリ選定どんな感じがいいんだろう?next-auth?javascript用のsdk?
- 最初よくわかってなくて、next-auth使えばいい感じにcognitoと連携できる?みたいに思っていましたが、今回の僕のケースだとnext-authは使えませんでした。(Next.jsの構成が、バックエンドにnodeの環境はなく、SSGして配信するためパターンで、Next.jsのapi routeの機能が使えなくて利用できなそうでした)
- next-authのドキュメント
- JavaScriptのライブラリで、aws-amplifyというのがあり、これを使ってCognitoへのリソースの操作をするのが良さそうでした。(名前がamplifyとなっていたので、amplify使うときに使うライブラリと勘違いしましたが、Cognito単独で使う場合も利用可能です)
独自のUIを作るパターンと、UIライブラリを使ったパターンがある?
- 今回は使いませんでしたが、提供されているUIライブラリを使う場合は、@aws-amplify/ui-reactを導入することでいい感じにやってくれるそうでした。
- UIライブラリを使うパターンの記事と独自UIを使うパターンの記事があり、初見だとどちらを参考にすればいいか迷いました。今回は独自UIだったので、UIライブラリを使っているパターンはスルーしました。
やりたかったこと
ドキュメントに、Cognitoを使用する際のシナリオが記載されています。このシナリオの中の、
- ユーザープールを使用して認証する
- ユーザープールを使用してサーバー側のリソースにアクセスする
が今回やりたかったことでした。
今回の具体的な構成については、バックエンドにLaravel、フロントエンドにNext.jsを使っています。Next.jsはSSGでHTMLを生成し、Amplifyで配信する構成です。Next.jsにaws-amplify(CognitoなどのAWSのリソースを扱えるライブラリ)を導入し、フロントからはこのライブラリを使ってCognitoのAPIを操作します。Cognitoで認証が済んだ後、Cognitoから受け取ったトークンを使ってLaravelのAPIにアクセスします。
aws-amplifyにはAuthのオブジェクトがあり、signUp
、signIn
、currentSession
などの関数が提供されているので、これらを使って認証の処理を行います。LaravelのAPIにリクエストを投げる際は、Cognitoから取得したトークンをheaderのAuthorizationに値を入れてリクエストを投げる、という流れです。UIに関しては、提供されているUIライブラリではなく、独自のUIを作成しました。
aws-amplify。Cognitoなどのリソースを操作するJavaScriptのライブラリ。Cognito使うだけでも、このライブラリが使えます。
AWS CLIを使ってのCognitoのリソース操作
フロントを構築する前に、さくっとCognitoのAPIを試してみたかったので、CLIを使って挙動の確認をしました。以下のようなコマンドが使えます。
// 例. サインアップ
$ aws cognito-idp sign-up --client-id [クライアントID] --username "[ユーザー名]" --password "[パスワード]" --validation-data '[バリデーションデータ]'
// 例. サインアップ後の確認
aws cognito-idp admin-confirm-sign-up --user-pool-id [ユーザープールID] --username [ユーザー名]
// 例. 認証フロー開始
aws cognito-idp admin-initiate-auth --user-pool-id [ユーザープールID] --client-id [クライアントID] --auth-flow ADMIN_USER_PASSWORD_AUTH --auth-parameters "USERNAME=[ユーザー名],PASSWORD=[パスワード]"
詳しくは、CLIのリファレンスです。
aws-amplifyを使ってのCognitoのリソース操作
aws-amplifyの使い方は、ドキュメントが参考になったのと、Authオブジェクトが持っているメソッドをながめて、どういうAPIが用意されてるのか確認しました。
詳しくは、aws-amplify のドキュメントです。
APIリファレンス
こちらが、Authのコードです。
他にもGitHubでCognitoとNext.jsが使われているコードを探して参考にしました。こちらが参考になりました。
ユーザー作成後の承認処理はLambdaで対応
Cognito上にユーザーを作成できたら、Cognitoに登録したユーザーのステータスを確認済みにする必要がありますが、今回のケースではSignUp(新規登録)のUIの都合上、Email/TELによる承認を行う流れがありませんでした。そのため、ユーザー作成後の承認処理をEmail/TELによる承認以外で対応しなければいけませんでした。確認済みのステータスに変更する他の方法としては、管理者による承認とLambdaでPreSignupイベントをトリガーとして承認するパターンがあり、今回はLambdaで対応しました。(SignUpした際に、確認コードによる承認を不要にできないかと調べてみたのですが、できなそうでした。)
以下の記事が大変参考になりました。
ユーザーアカウント確認の流れはこちらのドキュメントに記載されています。
Amplify Authメソッドで、承認コードなしでSingUpできないか探しているときに見つけたIssueです。管理系のメソッドをAuthでも使えるようにしてほしいと言った内容のIssueでしたが、管理系のメソッドは、ユースケース的にユーザー利用側のメソッドには必要ないっていうissueになっていました。
ステータスについて、具体的にはコンソールから見える確認ステータスのことです。
aws-amplify のAuthでリフレッシュトークンしてる処理を追ってみた
フロントからaws-amplifyを使ってCognitoへの認証を行うときに、トークンをリフレッシュする処理を書く必要があるのか、もしくはライブラリ側で実装してくれてるのか気になったので、処理を追ってみました。
constructorでconfigureが呼ばれてます。
configureの中で CognitoUserPool がnewするときに、wrapRefreshSessionCallbackがわたされてます。
CognitoUserPool はamazon-cognito-identity-jsから呼ばれます。
CognitoUserPoolはCognitoUserがnewするときに呼ばれます。
this.pool.wrapRefreshSessionCallbackは、refreshSessionの中で呼ばれます。
refreshSessionは、refreshSessionIfPossibleの中で呼ばれます。
refreshSessionIfPossibleは、getUserDataの中で呼ばれます。
getUserDataは、Auth.tsの中でいろんなんところで使われてそうでした。たとえば、currentUserPoolUserの中とかです。
currentUserPoolUserは、currentSessionの中とかで呼ばれてる。そのため、currentSessionなどgetUserDataを使ってる処理を実行したら、ライブラリ側で必要に応じて自動でトークンがリフレッシュされてそうでした。
上記、コード追ってみましたが、この辺りについてドキュメントにも記載があって、以下のように書いていました。Auth.currentSession()
を呼び出したら自動的にtokenもリフレッシュされるようです。
This method will automatically refresh the
accessToken
andidToken
if tokens are expired and a validrefreshToken
presented. So you can use this method to refresh the session if needed.12345
参考情報
Cognitoの概要的な記事です。
もともとは、amazon-cognito-identity-js だったけど、amplify-jsに統合されたってのを知った記事です。
つまづきポイント多すぎ、のところで同じようなことを思ったので、大変参考になりました。今回調べてた中で一番助かった記事でした。
Cognito試してみた後の消し方チュートリアルです。
Cognitoの概要を理解するために調べてた見つけた資料で、図がたくさんあってわかりやすかったです。
今回Laravel側は実装しませんでしたが、バックエンドがどうなってるかはこの記事が参考になりそうでした。
今回の記事とあんまり関係ありませんが、amplifyの推しポイントが書かれたこの記事も勉強になりました。
Discussion