このへんの記事を読みながらつくっていたら色々迷ったのでめも
やらかし1: Identity Provider を作っていなかった
IAM 管理画面で、ウェブアイデンティティ用の IAM Role を作っていたけど、プロバイダを特定の Cognito User Pool x App Client ではなく "Amazon Cognito" にしてた
これでやるとふつうに assume role したときに 403 になった
正しくはこう (ハンズオン資料から)
やらかし2: id token の形式が違う
AssumeRoleWithWebIdentityCommand はこういう風にコマンドを叩いているんだけど、ポイントとなるのは
- WebIdentityToken は JWT 形式 (i.e. type string)
- RoleSessionName は JWT から取り出した username
を入れる必要があること。
ソース: ハンズオンのここにあった Lambda の Zip を落としてそのコードを読んだ
import { STSClient, AssumeRoleWithWebIdentityCommand } from '@aws-sdk/client-sts' const REGION = 'ap-northeast-1' const stsClient = new STSClient({ region: REGION }) const username = jwtDecode(event['queryStringParameters']?.openIdToken)['cognito:username'] const command = new AssumeRoleWithWebIdentityCommand({ RoleArn: "YOUR_ROLE_ARN", RoleSessionName: username, WebIdentityToken: event['queryStringParameters']?.openIdToken, }) await stsClient.send(command)
やらかしパターン
(1) /oauth2/token
のレスポンスをそのまま WebIdentityToken につっこむ
→ id_token
以外のものも入ってるしそもそも JWT じゃないので NG
このエンドポイントからのレスポンスは https://docs.aws.amazon.com/cognito/latest/developerguide/token-endpoint.html にあるように、id_token, access_token, refresh_token がそれぞれ JWT で返ってくる。一方 command に送るのは id_token だけなので、そのまま送ると NG になる
{ "access_token":"eyJra1example", "id_token":"eyJra2example", "refresh_token":"eyJj3example", "token_type":"Bearer", "expires_in":3600 }
なので、 oauth2/token
からのレスポンスのうち id_token
プロパティだけを取り出すという作業が必要
const res = await fetch(...) // request to /oauth2/token const data = await res.json() const idToken = data.id_token
(2) id token をデコードして送る
これも「JWT 形式じゃないよ」と怒られるので、デコードせずに WebIdentityToken パラメータにつっこむ。