Cognitoは過去に何度か使ったことがありますが、色んな設定があり使い方も複雑で理解しづらく、この機会に改めて整理しようと思ったもののAWS認定のテキストでは説明がなんと5ページしかありませんでした。確かに試験で問われる要点だけならそんなに覚えることはないのですが、このまま進むのも何なのでちょっと立ち止まって色々と調べてみることにしました。
Cognitoフェデレーテッドアイデンティティ(IDプール)
Cognitoにはユーザープールとフェデレーテッドアイデンティティの2つの機能があり、先に登場したのがこのフェデレーテッドアイデンティティです。認証と認可のうち認可を担当し、AmazonやFacebookなどの認証プロバイダーによって認証が済んでいるユーザーに対してID(IDプールのアイデンティティID)を作成し、さらに予め設定されたIAMロールの一時的な認証情報(前回調べたアクセスキーとセッショントークン)を払い出すことによって、S3やDynamoDBなどの一部のAWSサービスへアクセスできるようになります。
Cognitoユーザープール
一方のユーザープールは認証を担当し、サインアップ(ユーザー作成)やサインイン(ログイン)、多要素認証(MFA)などの機能があります。作成するアプリケーションでユーザー管理が必要な場合に頼りになるサービスです。
Cognitoユーザープールの3つのトークン
ユーザープールにログインすると以下の3つのトークンを入手できます。
- IDトークン
- アクセストークン
- リフレッシュトークン
IDトークンには認証に関する情報が含まれています。どのユーザープールで認証したのかと認証したユーザーの一部の情報が読み取れます(Base64でデコードする必要があります)。
{
"origin_jti": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"sub": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"aud": "xxxxxxxxxxxxxxxxxxxxxxxxxx",
"event_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"token_use": "id",
"auth_time": 1629182147,
"iss": "https://cognito-idp.ap-northeast-1.amazonaws.com/{ユーザープールID}",
"cognito:username": "shion",
"exp": 1629185747,
"iat": 1629182147,
"jti": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"email": "xxx@gmail.com"
}
アクセストークンにはユーザープールに対する認可の情報が含まれています(こちらもBase64でデコードすると確認できます)。
{
"origin_jti": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"sub": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"event_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"token_use": "access",
"scope": "aws.cognito.signin.user.admin",
"auth_time": 1629182147,
"iss": "https://cognito-idp.ap-northeast-1.amazonaws.com/{ユーザープールID}",
"exp": 1629185747,
"iat": 1629182147,
"jti": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"client_id": "{アプリクライアントID}",
"username": "shion"
}
リフレッシュトークンは新しいIDトークンとアクセストークンを取得する時に使います。この2つのトークンは1時間で有効期限が切れてしまうので、定期的に新しいものに更新する必要があります。ちなみにリフレッシュトークンの有効期限は1時間から10年(!)までで自由に設定できます。
Cognito IDプールと連携するのはIDトークン
ユーザープール以外のサービスと連携する場合はIDトークンが使われます。例えばAPI Gatewayのオーソライザーにユーザープールを設定すると、AuthorizationヘッダーにIDトークンを設定しないと認証エラーとなります。
また、IDプールと連携して一時的な認証情報を取得する時に使うのもIDトークンです。例えばPython(boto3)では次のようにして取得できます。
import boto3
cognito_identity = boto3.client('cognito-identity')
# ユーザープールのIDトークンからIDプールのアイデンティティIDを取得する。
logins = {'cognito-idp.【リージョン】.amazonaws.com/【ユーザープールID】': '【IDトークン】'}
response = cognito_identity.get_id(IdentityPoolId='【IDプールID】', Logins=logins)
identity_id = response['IdentityId']
# IDプールのアイデンティティIDから一時的な認証情報を取得する。
response = cognito_identity.get_credentials_for_identity(IdentityId=identity_id, Logins=logins)
access_key_id = response['Credentials']['AccessKeyId']
secret_key = response['Credentials']['SecretKey']
session_token = response['Credentials']['SessionToken']
アクセストークンはユーザープールの属性を変更する時に使うので、IDトークンよりは限られた用途となります。
CognitoユーザープールはOpenID Connectに準拠している
以上がCognitoの簡単な説明となります。トークンの使い方などは試験にまず出ないと思いますが、気になって色々調べてみると面白いものです。
実際にはもっと細かい部分も調べていて、CognitoユーザープールはOpenID Connect(OIDC)という仕様に(完全ではないようですが)準拠しており、今回出てきたIDトークンやアクセストークンもそれに沿ったものとなっています。OIDCはOAuth 2.0と呼ばれる認可の仕様を認証にも使えるように拡張したもので、認証・認可の歴史やフローの詳細な仕様など調べれば調べるほど疑問が出てくるのですが…、キリがないので今回はここまでにしておきます。テキスト5ページしか進んでいませんしね!w