Cognitoで複数のIDP認証を単一ユーザー認証として扱うベストプラクティスを考えてみました🤔

Cognitoで複数のIDP認証を単一ユーザー認証として扱うベストプラクティスを考えてみました🤔

こんにちは!

認証基盤を自作構築する・・なんてことは最近全くしなくなりました。

近年では、Auth0やCognitoをはじめとした認証基盤を使用することが多いはずです。認証機能構築はアプリケーション開発にそれなりに複雑さをもたらすので、可能限りアプリケーション層とは疎結合に作りたいところです。

今回Cognitoへ登録された複数ユーザーを単一ユーザーとして扱う方法のベストプラクティスを紹介したいと思います。

想定する読者

  • Cognitoでユーザー管理を行っている方
  • Cognitoで複数ユーザーを単一ユーザーとして扱いたい方

はじめに

Cognitoのユーザープールサインインで、以下のようなユーザー認証情報をユーザプールへ蓄えることを想定します。

  • メールアドレスサインイン
  • Amazonサインイン
  • Facebookサインイン

認証方法は別だけど、単一ユーザーとして扱いたいシーンは多いはずです。

例えば、メールアドレスで登録したユーザーのマイページに「Facebook認証」ボタンがあるとします。Facebook認証をクリックすると、当然Facebook認証情報が現在のログイン中のユーザーに紐づくわけですが、ユーザープールの認証情報は別物として扱われますよね。

このようなケースに対して、方法として大きく分けて2つ実現方法があります。

パターン1:Cognito ID Pool を使用した ID の結合を行う

Cognito IDプールでは、複数のIDプロバイダーのユーザーのIDの結合し、一意な ID (IdentityId) を発行することが可能です。

User Pool から発行される ID Token と、 Facebook 等から発行されるアクセストークンを Logins として設定することで ID の結合が行われます。

Javascriptの実装参考はこちら

1度 ID の結合が行われると、結合を行った ID プロバイダーから発行された有効なトークンを1つ指定するのみで、再度結合した一意な ID を取得することが可能となります。

この一意な ID をベースに、直接 AWS サービスへアクセスを行う構成や、アプリケーションを使用する構成の検討が可能です。

この案の注意点としては、 Cognito ID Pool が対応している ID プロバイダーには限りがあります…。

パターン2:User Pool ユーザー同士のマッピングテーブルを用意する

User Pool ユーザーのsubに対して、連携したいIDプロバイダーのユーザーを識別可能な ID とのマッピングテーブルを作成する方法です。

例として Facebook の場合には、 Facebook のアクセストークンを検証する機能等を用いて、 Facebookの内部ユーザーIDとUser Poolユーザーのsub値を保存するような形となります。

1と2どちらがいいのか?

  • 1の方はプログラミングコストが低い(半自動的に構築可能)
  • 2の方が自分で定義した様々なIDPと連携が可能である

どちらも一長一短ですね。私としては、まだ仕様が固まっていない状況であれば、2の方を推奨します。(仕様が定まっていない状態で認証IDプロバイダーをCognito依存で決めてしまうのは危険ですので)

まとめ

認証基盤開発の成功の秘訣は、認証したいIDPは何なのか、また認証をどのようにしたいのかを事前にしっかり決めることです。(MFA必須なのか、認証状態の生存時間はどの程度の時間幅にするのか)

私たちが普段開発支援を行う際は、新規事業などの仕様が決まってないアジャイル開発が多数ですので、パターン2の方を採用して認証基盤の開発を行っています。

逆に業務アプリなどの場合はSNS認証などはまず行わないので、メールアドレスなどの通常のユーザープールサインインを用いて開発を行いますので、パターン2のようなマッピングテーブルの開発は不要ですね。

企業様によってはLDAP認証などを必要とするケースがありますが、その場合は別途認証用のエンドポイントを提供いただければ問題なく開発は可能です。(認証基板がAWS外になった場合、AWS上での認可の仕組みの提供が複雑になりますが…)