AmplifyでCognitoのHosted UIを利用した認証を最低限の実装で動かしてみて動作を理解する

AmplifyとCognitoを利用すると、Amplifyがうまいことやってくれるので、プログラム開発者は認証フローを意識することなく認証機能が実装できます。 その、うまいことってのが具体的に何をやっているのかを暴きます。
2020.06.22

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

Amplifyを使うと、Cognitoを利用して簡単に認証機能を作れて便利です。
詳しくは弊社ブログをご覧ください。

また、こういったログインのほかに、CognitoにはホストされたUIを利用してユーザー認証をするという機能があります。 イメージ動画を作成したのでこちらを御覧ください。

この方法を採用すると何がうれしいかというと、外部IDプロバイダ(例えば、Facebookでログインするとか、Googleでログインするといったやつ)を追加したときに、こんな形でログインUIをCognitoが自動で追加してくれます。

ただし、ログインUI用の別URLにジャンプする動作をするという関係上、Cognitoのユーザーだけを利用する場合とは異なり、認証フローが大きく変わります

その認証フローが大きく変わるという部分を Amplifyがうまいことやってくれて 、 プログラム開発者はほとんど意識することなく認証機能を実装できます。スゴイですね!

Amplifyの公式ドキュメントに、ReactでCognitoを利用してFacebookログインやGoogleログインを実装するサンプルがあります。 詳しくはこちらを御覧ください。

動くものを作りたいだけであれば、ここまで読んでいただければ大丈夫です。
ありがとうございました。


ここから先は、「うまいことってなんなんだよ。全然納得できない。具体的に何をどうしてるんだよ。」 みたいなことを考えてしまう私みたいなひねくれ者のために、 知らなくても困らないけど、知っているともっと楽しめるかもしれない、 AmplifyとCognitoでホストされたUIがどんな認証フローをとっているのか? そして、具体的に何をうまいことやってくれているのか?という話をします。

構成概要図

サンプルとしてAmplifyとCognitoユーザープールを使ってざっくりこんな感じの環境を作ります。

今回、必要最低限の実装ということで、画面は1つで、ReactやVueのようなSPAフレームワークは使いません。

認証フローの話をする前に、いったん環境を構築してみましょう。

動くものがあったほうが理解しやすいと思います。

サンプルプログラム置き場

今回作成したプログラムはGitHubで公開しています。 実際に動かしてみたい方はこちらから git clone してください。

前提条件

サンプルプログラムを動かす場合、次のコマンドが利用できるようにインストールをしておいてください。

$ node --version
v12.16.2
$ npm --version
6.14.5
$ aws --version
aws-cli/2.0.10 Python/3.7.4 Darwin/19.5.0 botocore/2.0.0dev14

Cognito環境の構築

まずは git clone して環境一式をGitHubから取ってきます。

$ git clone https://github.com/rednes/cognito-simple-example-for-external-idp.git
$ cd cognito-simple-example-for-external-idp

次にCloudFormationを利用して、Cognitoの環境を作ります。 次のコマンドを実行すると、Cognitoの環境が作れます。
コマンドが具体的に何をしているか気になる方は、 package.json で定義していますので、詳細はそちらを御覧ください。

$ export AWS_DEFAULT_PROFILE=<<YOUR_AWS_PROFILE>>
$ npm run cfn-deploy

しばらくすると、CloudFormationでCognitoの環境構築が完了します。 次のコマンドで出力結果を確認してください。 次のような形で結果が返ってくれば大丈夫です。

$ npm run cfn-describe
---------------------------------------------------------
|                    DescribeStacks                     |
+------------------------+------------------------------+
|  CognitoRegion         |  ap-northeast-1              |
|  CognitoUserPool       |  ap-northeast-1_XXXXXXXXX    |
|  CognitoUserPoolClient |  XXXXXXXXXXXXXXXXXXXXXXXXXXX |
+------------------------+------------------------------+

次に、ひとつだけマネジメントコンソールで設定してほしい作業があります。

Cognitoがホストしているログイン用のURLは、Cognitoが用意する画面です。 そのため、アプリケーションとはまったく別ドメインのサイトになります。

このサブドメインの名前を決めて、Cognitoで設定する必要があります。 サブドメインの設定手順を示します。


Cognitoユーザープールのマネジメントコンソール画面を開き、 CognitoSimpleExampleUsers という名前のユーザープールができているので開きます。

左側のメニューのドメイン名を選択して、ドメインのプレフィックス を入力してください。 ドメインのプレフィックスは後で利用するのでメモしておいてください。

以上でCognitoの環境構築は終了です。

アプリケーションの設定

アプリケーションの設定ファイルを、Cognitoの環境とあわせた値に変更します。

/public/js/amplifyConfig.js.example ファイルを /public/js/amplifyConfig.js にコピーして、さきほどメモしたドメインのプレフィックスを CognitoDomainPrefix に入力してください。
CognitoUserPool等の値は、さきほど実行した npm run cfn-describe コマンドで確認できるのでこれも入力してください。

$ npm run cfn-describe
---------------------------------------------------------
|                    DescribeStacks                     |
+------------------------+------------------------------+
|  CognitoRegion         |  ap-northeast-1              |
|  CognitoUserPool       |  ap-northeast-1_XXXXXXXXX    |
|  CognitoUserPoolClient |  XXXXXXXXXXXXXXXXXXXXXXXXXXX |
+------------------------+------------------------------+

/public/js/amplifyConfig.js

let CognitoRegion = 'ap-northeast-1';
let CognitoUserPool = 'ap-northeast-1_XXXXXXXX';
let CognitoUserPoolClient = 'dummy';

let CognitoDomainPrefix = 'dummy';

let amplifyConfig = {
    Auth: {
        region: CognitoRegion,
        userPoolId: CognitoUserPool,
        userPoolWebClientId : CognitoUserPoolClient,
        oauth: {
            domain: `${CognitoDomainPrefix}.auth.${CognitoRegion}.amazoncognito.com`,
            scope: ['openid'],
            redirectSignIn: 'http://localhost:3000',
            redirectSignOut: 'http://localhost:3000',
            responseType: 'code'
        }
    }
};

次に、ローカルでexpressサーバーを動かすために、次のコマンドを実行してnodeパッケージをインストールしてください。

$ npm install --production

次のコマンドを実行して、待機状態になれば成功です。 http://localhost:3000 でアクセスできるローカルサーバーができました。

$ npm start
Node.js is listening to PORT:3000

ホストされたUIを利用したログインの流れを確認してみる

ブラウザから http://localhost:3000 にアクセスすると、こんな感じのSign Inボタンがあるだけの画面が表示されます。

ここでSing Inボタンを押すと、Cognitoのログイン画面に飛びます。

ユーザー登録の説明を省いて、すでにユーザーは登録済みという前提で進めます。
E-mail/Passwordを入力してサインインします。

そうすると、元のページに戻ってユーザー認証が完了し、Cognitoの発行したトークンがベロっと画面に表示されるというアプリケーションです。

Sign Outボタンを押すと、サインアウトされてトークンの表示もなくなります。

ただこれだけのシンプルアプリケーションです。

それではコードを読んでいきましょう。 60行程度なので、すぐ読めると思います。

コードの解説

server.js

まず、 server.js で動かしているexpressです。 これ自体はほとんど何もしていません。

これは public/js フォルダに入っている、 aws-amplify.min.js 等のローカルにあるJavaScriptファイルをHTMLから読み込みたいという理由だけで動作させています。

server.js がやっているのは、トップページにアクセスがあったとき、 views/index.ejs を何も手を加えずに配信しているだけです。

そのため、メインのロジックは views/index.ejs のscriptタグに書いています。

views/index.ejs

views/index.ejs もやっていることはシンプルです。

10行目の onload で、画面の読み込みが終わったら24行目からの onLoad ファンクションを実行しています。

そして ./js/aws-amplify.min.js からAmplifyとAuthクラスを取り出して、28行目の Amplify.configure でamplifyの設定をしています。

30行目ではaddEventListnerを使って、Sign Inボタンが押されたら Auth.federatedSignIn を実行するように設定しています。 このファンクションが、CognitoのホストされたUIへリダイレクトしている処理 の正体です。

そして38行目で Auth.currentSession を使って、ログインしているユーザーの情報を取得しています。
取得できたら document.getElementById('sessionInfo').innerText にベロっと吐き出しています。
取得できなかったら(ユーザーがログインしていなかったら)、コンソールにerrorだけ吐き出して何もしません。

こんな感じのJavaScriptです。

ここで何が言いたいかというと、プログラムを書く際に 明示的に書いている認証処理 は48行目の Auth.federatedSignIn だけということです。
これ以外ほぼ何もせずに認証処理が実装できています。スゴイですね!

プログラムが具体的にイメージできたところで、そろそろCognitoの認証フローの話に入っていきます。

Cognitoの認証フロー

CognitoのOAuthフローとして、次の 3つのフロー を利用することが許可されています。

  • Authorization code grant
  • Implicit grant
  • Client credentials

Authorization code grantはPKCEを併用できます。
ですので、4種類あると言ってもよいかもしれません。

  • Authorization code grant
    • PKCE未使用
    • PKCE併用
  • Implicit grant
  • Client credentials

参考: サインアップおよびサインインに Amazon Cognito のホストされた UI を使用する - Amazon Cognito

本筋から外れるので、本ブログでは 各フローについての詳細までは立ち入りません
どういう場合にどのフローを選択するかだけざっと説明します。

  • Authorization code grant(基本的にこのフローが推奨)
    • PKCE未使用(Webアプリケーション等、トークンをサーバが仲介して取得する場合。通常クライアントシークレットを設定する。)
    • PKCE併用(SPAやモバイルアプリ等、トークンをユーザーが直接取得する場合)
  • Implicit grant(Authorization code grantが不可能な場合選択。PKCE併用したcode grantが推奨される)
  • Client credentials(エンドユーザーが認証に使うフローではない)

各フローはOAuth 2.0で定義されている認可フローとほぼ同じものですので、各フローの詳細はOAuth2.0認可フローをご参照ください。参考資料をブログの最後に貼っておきます。

今回のサンプルアプリケーションは、 トークンをユーザーがJavaScriptを使って直接取得 しておりSPAに相当します。
よって、推奨されている PKCEを併用するAuthorization code grant 決め打ちで説明します。

それでは、 PKCEを併用するAuthorization code grant フローとは何なのでしょうか?

PKCEを使用しないAuthorization code grant

いきなりPKCEを併用するAuthorization code grantの話をすると混乱するので、 いったんPKCEを使用しない場合のフローについて説明します。

本ブログでは、OAuth2.0の認可フローである一般的なAuthorization code grantの話というよりは、 CognitoのAuthorization code grantフローがどういう動きをしているのかという具体的な動きを説明します。

まずは、Authorization code grantフローの全体像をシーケンス図で示します。

Authorization code grant フローは、次のステップで進んでいきます。

ユーザーがアプリケーションに対してログイン要求を出すと、 アプリケーションはCognitoの 認可エンドポイント に対して認証リクエストを投げるための、リダイレクトレスポンスをユーザーに返します。(フロー図の0102

そうすると、ユーザーは認可エンドポイントにリダイレクトされ、Cognitoに認証リクエストを投げることになります。 Cognitoはそれに応じてリダイレクトレスポンスで ログインエンドポイント(ログイン画面のURL) を返します。(フロー図の0304

リダイレクトレスポンスが返ってくるので、ユーザーはログイン画面にリダイレクトされます。 ログイン画面が表示されるので、ユーザーはID/Passwordを入力してユーザーによる認証を行います。(フロー図の0507

そうすると、Cognitoは 認可コード を発行して、リダイレクトレスポンスのURLクエリパラメーターに認可コードを添えてユーザーに返します。(フロー図の08

リダイレクトレスポンスが返ってくるので、ユーザーは認可コードつきでアプリケーションのCallback URLへリダイレクトされます。(フロー図の09

Callback URLのアクセスで認可コードを受け取ったアプリケーションは、その認可コードを使ってCognitoの トークンエンドポイント に対してトークンリクエストを投げます。(フロー図の11

Cognitoはその認可コードが有効であると判断すれば、IDトークン,アクセストークン,リフレッシュトークン をアプリケーションに返します。(フロー図の12

アプリケーションはIDトークンの検証をして問題なければ、ログイン完了したことをユーザーに伝えます。(フロー図の1314

これが、 Authorization code grant フローの流れです。


これを読んで、Authorization code grant のイメージ、湧きましたでしょうか?

私はこの説明を文章で読んだけでは、さっぱりわかりませんでした。

具体的にCognitoに対して出しているリクエストを自分の手で実行してみると理解が進むと思います。
ですので、実際にシェルとブラウザで Authorization code grant フローを体験してみましょう。

シェルとブラウザでAuthorization code grantをやってみる

Authorization code grant フローのシーケンス図を再掲します。

まずは、認証リクエストをCognitoの認可エンドポイントに送り、リダイレクトレスポンスを受け取るところをやってみます。(フロー図の0304

Cognitoの認可エンドポイントについての詳細は、こちらのドキュメントをご参照ください。

リクエストの送信先とするCognitoは、先ほどのサンプルアプリケーション用に構築したものを利用します。
そして、ドメイン名はログイン画面のURLのドメイン名と同じです。

つまり、ドメインプレフィックスを、 cognito-domain-prefix として、リージョンを ap-northeast-1 で構築していた場合、認可エンドポイントのURLは、 https://cognito-domain-prefix.auth.ap-northeast-1.amazoncognito.com/oauth2/authorize になります。

よって、次のように curl コマンドを実行することで、この認可エンドポイントに対して認証リクエストを投げることができます。

$ CognitoRegion=ap-northeast-1
$ CognitoUserPoolClient=<<YOUR_COGNITO_CLIENT_ID>>
$ CognitoDomainPrefix=<<YOUR_COGNITO_DOMAIN_PREFIX>>
$ CognitoDomain=$(echo ${CognitoDomainPrefix}.auth.${CognitoRegion}.amazoncognito.com)
$ curl -i "https://${CognitoDomain}/oauth2/authorize?response_type=code&client_id=${CognitoUserPoolClient}&redirect_uri=http://localhost:3000&state=xyz&scope=openid"

クエリパラメーターの項目と設定値について説明します。

response_type
code または token を指定します。認可コードを要求するAuthorization code grantの場合、 code を指定します。よって、今回は code を指定します。
client_id
CognitoユーザープールのクライアントIDを指定します。
redirect_uri
認可コードを返すリダイレクト先のURLを指定します。今回は、http://localhost:3000 を指定します。
state
Cognitoがクライアントにリダイレクトして戻るときに、この値を含めるようになります。オプション値だが、CSRF攻撃を防ぐために設定することが強く推奨されています。
scope
スコープを指定します。OIDC認証をする場合、openid の指定が必須です。今回は opeind を指定します。

実際にこのリクエストを投げてみましょう。

そうすると、 302リダイレクト のレスポンスが返ってきて、 Locationレスポンスヘッダー にリダイレクト先のURLが示されていることがわかります。

HTTP/2 302
location: https://<<YOUR_COGNITO_DOMAIN_PREFIX>>.auth.ap-northeast-1.amazoncognito.com/login?response_type=code&client_id=<<YOUR_COGNITO_CLIENT_ID>>&redirect_uri=http%3A%2F%2Flocalhost%3A3000&state=xyz&scope=openid

また、LocationのURLから、リダイレクト先はログインエンドポイントであることがわかります。
このログインエンドポイントというのが、いわゆるCognitoがホストしているログイン画面のURLのことです。

次にこのリダイレクト先のURLへブラウザを使ってアクセスしてみます。(フロー図の0508

そうするとこのようにCognitoのログイン画面が表示されます。 ログインするとlocalhostへリダイレクトされてくるので、ローカルサーバーがリクエストを受け取らないようにexpressサーバは終了しておいてください。

E-mail/Passwordを入力してログインすると、Cognitoからリダイレクトレスポンスが返ってきます。

リダイレクトレスポンスは次のような形をしています。

http://localhost:3000/?code=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX&state=xyz

state には認証リクエストで指定したxyzが入っています。 通常CSRF攻撃を防ぐため、認証リクエストで送信した state をアプリケーション側で保持しておき、リダイレクトで返ってきたstate と一致しているかをアプリケーション側でチェックします。
code の値に入っているものが 認可コード です。 認可コード はトークンリクエストの際に必要です。

次に IDトークンアクセストークン の取得処理です。 トークンエンドポイントに対してトークンリクエストをやってみます。(フロー図の1112

Callbackで受け取った 認可コードAuthorizationCode 環境変数に格納すると、次のように curl コマンドを実行することで、トークンエンドポイントに対してトークンリクエストを投げることができます。

$ AuthorizationCode=<<YOUR_AUTORIZATION_CODE>>
$ CognitoRegion=ap-northeast-1
$ CognitoUserPoolClient=<<YOUR_COGNITO_CLIENT_ID>>
$ CognitoDomainPrefix=<<YOUR_COGNITO_DOMAIN_PREFIX>>
$ CognitoDomain=$(echo ${CognitoDomainPrefix}.auth.${CognitoRegion}.amazoncognito.com)
$ curl -X POST \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=authorization_code" \
  -d "client_id=${CognitoUserPoolClient}" \
  -d "scope=openid" \
  -d "redirect_uri=http://localhost:3000" \
  -d "code=${AuthorizationCode}" \
  "https://${CognitoDomain}/oauth2/token"

パラメーターの項目と設定値について説明します。

grant_type
authorization_code, refresh_token または client_credentials を指定します。今回はAuthorization code grantに沿ってトークンを要求しているので、authorization_code を指定します。
client_id
CognitoユーザープールのクライアントIDを指定します。
scope
スコープを指定します。OIDC認証をする場合、openid の指定が必須です。今回は opeind を指定します。
redirect_uri
認可コードを要求したときに指定した redirect_uri と同じ値を設定する必要があります。今回は、http://localhost:3000 を指定します。
code
認可コードを指定します。

トークンリクエストが成功すると、トークンレスポンスが次のような形で返ってきます。

{
    "id_token": "eyJraWQ...5peOLw",
    "access_token": "eyJ...NISbew",
    "refresh_token": "ey...Kz7AnA",
    "expires_in": 3600,
    "token_type": "Bearer"
}

この、 id_token の値が IDトークン で、 access_token の値が アクセストークン です。

これで、Cognitoからトークンが取得できてユーザーのログインが完了しました。

最後に、この IDトークン の中身を見てましょう。 IDトークンJWT形式 でユーザーに関する情報が入っています。

そのため、jwt.io等のサイトやライブラリを使って中身を確認できます。

jwt.ioにIDトークンをコピー&ペーストしてみると、このように中に入っているユーザー情報を確認できます。

PKCEを併用するAuthorization code grant

ここまでPKCEを使用しないAuthorization code grantの話をしてきました。
PKCEを併用する場合もフロー自体は変わりません。 認可コードの横取り攻撃の対策のために、随所でパラメーターのやりとりが追加されます。

OAuth2.0のPKCEを理解するには、ゲストブロガーとしてAuth0社の筒井さんに書いていただいたこのブログがわかりやすいです。

PKCEの一般的な話はこちらのブログに説明をゆずり、本ブログではCognitoの具体的な動きを見ていきます。

PKCEを併用するAuthorization code grantフローの全体像をシーケンス図で示します。

PKCEを使用しないAuthorization code grant フローから追加された、赤字で書いた処理だけを説明します。

まず認証リクエストを送る前に、アプリケーション側で code_verifier の発行と保存をし、code_verifiercode_challenge_method に沿った方法で code_challenge に変換します。(フロー図の02

ちなみに、Cognitoが対応しているcode_challenge_method は現段階では S256 のみです。

その後、パラメーターに code_challengecode_challenge_method を追加して認可エンドポイントに認証リクエストを投げるための、リダイレクトレスポンスをユーザーに返します。(フロー図の03

そうすると、ユーザーは認可エンドポイントにリダイレクトされ、code_challengecode_challenge_method パラメーターとあわせて、Cognitoに認証リクエストを投げることになります。 Cognitoはそれに応じてリダイレクトレスポンスで ログインエンドポイント(ログイン画面のURL) を返します。(フロー図の0405

その後は、トークンリクエストする直前まで飛んで、Callback URL経由で認可コードを受け取った後、保存していた code_verifier の読込と破棄をします。(フロー図の12

その後、パラメーターに code_verifier を追加してトークンエンドポイントにトークンリクエストを投げます。(フロー図の13

これが、 PKCEを併用したAuthorization code grant フローです。

PKCEを併用したAuthorization code grantフローでの認証を採用する場合、アプリケーション側はこのフローに沿ってCognitoとパラメーターをやりとりする実装が必要です。

Amplifyも当然、このフローに沿って認証処理をしています。
Cognitoの認証フローが理解できたところで、いよいよAmplifyがうまいことやってくれていることを暴いていきます。

Amplifyがうまいことやってくれていること

Amplifyの設定

まず、Amplifyがうまいことやるための設定についてです。
Amplify.configure の引数としているこの値が重要です。

この設定で、AmplifyとCognitoがどの認証フローでやりとりするのか、どのCognitoのエンドポインと通信したいのか、リダイレクト時のコールバックURLが何なのかを定義しています。

/public/js/amplifyCnofig.js

let amplifyConfig = {
    Auth: {
        region: CognitoRegion,
        userPoolId: CognitoUserPool,
        userPoolWebClientId : CognitoUserPoolClient,
        oauth: {
            domain: `${CognitoDomainPrefix}.auth.${Region}.amazoncognito.com`,
            scope: ['openid'],
            redirectSignIn: 'http://localhost:3000',
            redirectSignOut: 'http://localhost:3000',
            responseType: 'code'
        }
    }
};

参考: Authentication - Social sign-in (OAuth) - Amplify Docs

特に重要なパラメーターの項目と設定値について説明します。

Auth.userPoolWebClientId
CognitoユーザープールのクライアントIDを指定します。認証リクエストやトークンリクエストする際に、クライアントIDとして利用されます。
Auth.oauth.domin
認可エンドポイント等、各エンドポイントにアクセスする際のCognitoのエンドポイントのドメイン名として利用されます。
Auth.oauth.scope
スコープを指定します。OIDC認証をする場合、 openid の指定が必須です。今回は opeind を指定しています。
Auth.oauth.redirectSignIn
認証リクエストやトークンリクエストをする際のリダイレクト先URLを指定します。今回は、 http://localhost:3000 を指定しています。
Auth.oauth.responseType
code または token を指定します。Authorzation code grantフローを採用する場合、code を指定します。Implicit grantフローを採用する場合、 token を指定します。今回は、Authorzation code grantフローを採用したいので、 code を指定します。

ちなみに、 Auth.oauth.redirectSignIn はCognitoのこの画面で設定する コールバックURL と一致していないと、Cognito側が受け付けてくれません。

また、Auth.oauth.responseTypecode を指定する場合は、 Authorzation code grant フローを採用することになります。その場合、Cognitoのこの画面で Authorization code grant を指定する必要があります。
token を指定する場合は、 Implicit grant フローを採用することにります。その場合、 Implicit grant を指定する必要があります。

また、 Auth.oauth.scope で指定できるスコープは、Cognitoのこの画面で 許可されているOAuthスコープ に限ります。

参考: ユーザープールのアプリクライアントの設定 - Amazon Cognito

Amplifyの動作

PKCEを併用するAuthorization code grant フローのシーケンス図を再掲します。

Amplifyが何をうまいことやっているのか明らかにするために、 先ほど構築したサンプルアプリケーションとブラウザの開発者ツールを使ってAmplifyの動きを追ってみます。

Auth.federatedSignIn にブレークポイントをしかけた上で、Sign Inボタンをおして Auth.federatedSignIn を実行し、ステップインで処理を追っていきます。

そうすると、セッションストレージに statecode_verifier を保存している動きが見えます。(フロー図の02

その後、ブレークから復帰してCognitoのログイン画面まで遷移すると、Cognitoの認可エンドポイントに対して、state, code_challenge, code_challenge_method 等をパラメーターとして認証リクエストをしている動きが見えます。(フロー図の0304

その後、認可エンドポイントからリダイレクトレスポンスを受け取り、ログインエンドポイントへリダイレクトしている動きが見えます。(フロー図の0506

つまり、 Auth.federatedSignIn (&ブラウザのリダイレクト)が次のような処理を開発者が気にしなくていいように隠蔽してくれています。

そして、認証フローを理解していると次の疑問が出てきます。
「それじゃあ、トークンリクエストはいったいどこの誰がやっているのだろう?

これは、Amplifyのソースを追っていくとわかります。 Amplify.configure がやってくれています。

これも、サンプルアプリケーションとブラウザの開発者ツールを使ってAmplifyの動きを追ってみます。

今のままだと、アクセスした瞬間に onLoad() が走ってしまうので、 viws/index.ejs のbodyを書き換えて、 onLoad() の実行をいったん止めます。 そして、 Amplify.configure にブレークポイントを設定します。

<!--<body onload="onLoad()">-->
<body>

ブレークポイントをしかけた上で、consoleから手動で onLoad() を実行します。

そして Amplify.configure からステップインで処理を追っていくと、セッションストレージから statecode_verifier が削除されている動きが見えます。(フロー図の12

そして、Cognitoトークンエンドポイントに対して、 code, code_verifier 等をパラメーターとしてトークンリクエストが投げられて。(フロー図の13

トークンレスポンスを受け取るという動きも見えます。(フロー図の14

ブレークから復帰して最後まで進めると、最終的にはローカルストレージに IDトークンアクセストークン が保存されていることがわかります。

つまり、 Amplify.configure (&ブラウザのリダイレクト)が次のような処理を開発者が気にしなくていいように隠蔽してくれています。

結論として、これまで説明したような認証フローの処理を Amplifyがうまいことやってくれる ので、 プログラム開発者は認証フローをほとんど意識することなく、 Auth.federatedSignIn をするだけで認証機能を実装できるというわけです。 スゴイですね。

終わりに

知らなくても困らないけど、知っているとおもしろいかもしれない Amplify の認証の裏話について語りました。

実際この認証フローのアプリケーション側を自分で実装しようとするととても面倒くさいので、 Amplify が隠蔽してうまいことやってくれるのはとてもうれしいですね。

認証部分はぜひAmplify等のライブラリを使って楽をしましょう。

ちなみに、クラスメソッドでは認証を楽にするSaaSサービス、 Auth0 の取り扱いもございます。

認証でお困りの際には、お気軽にクラスメソッドまでお問い合わせください。

参考資料