なぜAuth0?

CognitoへTwitterログインを実装したかったからです。Cognito User Poolのフェデレーションサインインは、独自IDPを追加する場合、OpenIDConnect, SAMLしか対応できない。TwitterはOAuth2.0だから非対応だ。開発中のアプリ要件にTwitterログインがあるのでどうしても避けることができない。

一応補足すると、Identity Pool使用すればTwitterのクライアントID・シークレットIDでSTSトークンを受け取ることが可能。
がしかし、今回下記のようにCognitoUserPoolトークンによる認証トークン取得フローが必要だ。

では設定してみる

Auth0の設定画面よりアプリケーションを作成

CREATE APPLICATIONをクリックし任意の名称でアプリケーションを作成

SPA(Single PageWeb Application)を選択

「Addons」より「SAML2 WEB APP2」をクリック

「Application Callback URL 」へCognitoのコールバックURLを入力

Settingsのコードを書きのように書き換える

logout.callbackのURLはアプリケーションのURLを指定します。

{
  "audience": "urn:amazon:cognito:sp:ap-northeast-1UserPoolID",
  "nameIdentifierFormat": "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent",
  "logout": {
    "callback": "http://localhost:3000",
    "slo_enabled": true
  },
  "mappings": {
    "user_id": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier",
    "email": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress",
    "name": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name",
    "given_name": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname",
    "family_name": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname",
    "upn": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn",
    "groups": "http://schemas.xmlsoap.org/claims/Group"
  }
}

疑問なのは、Cognitoへコールバックしたら、そこでアプリケーションのコールバックURLに帰ってきてくれる予想でしたが、自分はうまくいきませんでした...。これだとローカル開発時にいちいちlogout.callbackを変更しないといけないし、開発効率が下がりそうな気が。コールバック単位でAuth0にアプリケーションを作成するのも面倒くさい。

「Usage 」よりCognitoのSAMLプロバイダーにて使用するキー情報をダウンロード

Cognitoユーザープールへ設定

SAML IDPの追加

先ほどダウンロードしたキー情報をアップロードし、プロバイダーの作成をクリックし作成を行います。ここでエラー出る場合はキー情報をもう一度ダウンロードして試してみてください。

ここで注意なのは、Facebookでもなんでもいいのですが、外部認証プロバイダーを一つ以上登録しておかないと、HostedUI(Cognitoで標準で用意されているログイン画面)を使用できないので、つまりドメイン及びアプリクライアントを作成できない。

外部プロバイダーによるサインインする際は、使用しなくて一つ以上適当なアクセスキー・シークレットキーで登録しておこう。(例えば access_key = XXXXXX, secret_key = XXXXXX)

アプリクライアントにてAuth0認証有効

Auth0を追加し、変更を保存。

JSコード

私はAmplifyユーザーなので、Amplifyのコードを載せておく。

import {Auth, API, graphqlOperation} from 'aws-amplify';
await Auth.federatedSignIn({provider: 'Auth0'})

これであとは実行すればAuth0の画面へリダイレクトされる。

続いて、最後にログアウトの実装を見る。これをやらないとAuth0からログアウトしたことにならず、同一ブラウザでキャッシュクリアしないとAuth0認証画面が表示されない。(自動的に前回のログイン情報で認証処理を行ってしまう)

await Auth.signOut()

手順の最初の方でユーザープールへのSAMLプロバイダー追加の際にチェックした「Idpサインアウトフローの有効」にチェックを入れると自動的にAuth0からもSignOut処理をしてくれる。

逆にチェックを入れないとローカルストレージの破棄しかしてくれない。

所感

今のどきのアプリであれば、SNSログインなどは当たり前だと感じる。

OAuth2.0しか対応しないIDPへのログイン要件がある場合は、Auth0の導入を検討した方が無難だろう。

実際問題、Auth0を採用せずTwitterログインを実現しようとすると、IdentityProviderに直接認証する感じになるので、ユーザープールのグループを判別した権限管理などが行えない。(厳格にはできるけど独自設定しないといけないのでAmplifyなどで自動化して構築している場合はほぼほぼ詰む)