Cognitoユーザープールの認証後にIDプールで権限を与える(Authorization code grant編)
以下のページで、CognitoユーザープールおよびIDプールを使用し、OAuthフローはImplicit grant(暗黙の付与)の条件で、サインインユーザーにAWSリソースへアクセスするための権限を付与する構成を確認しました。
今回はOAuthフローをAuthorization code grant(認可コードの付与)に設定した上で、同様の構成を作成します。
構築する環境
構成は前回と同様です。変更点は、Cognitoユーザープールのおいて、OauthフローをAuthorization code grantに設定しただけです。
Authorization code grantによる処理の流れを確認します。
Authorization code grantの場合、直接トークンを取得することはできず、代わりに認可コードを取得できます。今回は以下の流れで処理を行います。
- ホストされたUIページからサインインを行う。
- URLパラメータから認可コードを取得する。
- 認可コードをユーザープールのトークンエンドポイントにPOSTし、トークンを取得する。
- トークンを使用してIDプールにアクセスし、一時的なクリデンシャルを取得後、SSMにアクセスする。
トークンエンドポイントに関する詳細は、以下のページをご確認ください。
https://docs.aws.amazon.com/ja_jp/cognito/latest/developerguide/token-endpoint.html
CloudFormationテンプレートファイル
上記の構成をCloudFormationで構築します。
以下のURLに、CloudFormationテンプレートに加え、ブラウザスクリプト等を配置してます。
https://github.com/awstut-an-r/awstut-fa/tree/main/035
ポイント解説
大部分が前回の構成と同様ですので、詳細はそちらをご確認ください。
本ページでは、Authorization code grantに関する内容に触れます。
CognitoユーザープールのOAuthフロー
Resources:
UserPoolClient:
Type: AWS::Cognito::UserPoolClient
Properties:
AllowedOAuthFlowsUserPoolClient: true
AllowedOAuthFlows:
- code
#- implicit
AllowedOAuthScopes:
- openid
- profile
CallbackURLs:
- !Sub "${BucketWesSiteEndpointUrl}/${SigninHtml}"
ClientName: !Sub ${Prefix}-UserPoolClient
ExplicitAuthFlows:
- ALLOW_REFRESH_TOKEN_AUTH
- ALLOW_USER_SRP_AUTH
LogoutURLs:
- !Sub "${BucketWesSiteEndpointUrl}/${SignoutHtml}"
SupportedIdentityProviders:
- COGNITO
UserPoolId: !Ref UserPool
Code language: YAML (yaml)
AllowedOAuthFlowsプロパティでOAuthフローを設定します。
今回はAuthorization code grantを使用しますので、「code」を指定します。
次にホストされたUIによるサインイン/サインアウトページのURLを確認します。
それぞれ以下のURLとなります。
- サインインページ用URL:https://[プレフィックス].auth.ap-northeast-1.amazoncognito.com/login?response_type=code&client_id=[アプリクライアントID]&redirect_uri=[サインイン後のリダイレクト先URL]
- サインアウトページ用URL:”https://[プレフィックス].auth.ap-northeast-1.amazoncognito.com/logout?response_type=code&client_id=[アプリクライアントID]&logout_uri=[サインアウト後のリダイレクト先URL]
ポイントはURLパラメータのresponse_typeです。
Authorization code grantの場合、認可コードを取得できますので、本パラメータを「code」に設定します。
ブラウザスクリプト
JavaScriptを使用して、サインイン後のCognito機能を実装します。
AWS SDK for JavaScript v3を使用して、ブラウザスクリプトを作成する手順は、以下のページをご確認ください。
本ページでは、Authorization code grantでトークンを受け取るためにポイントとなる箇所を取り上げます。
認可コードとトークンエンドポイントURL
ホストされたUIによって払い出された認可コードを取得します。
const params = new URLSearchParams(window.location.search);
const code = params.get("code");
const tokenEndpoint = `https://${DOMAIN}.auth.${REGION}.amazoncognito.com/oauth2/token?grant_type=authorization_code&client_id=${CLIENT_ID}&redirect_uri=${REDIRECT_URI}&code=${code}`;
Code language: JavaScript (javascript)
認可コードはURLパラメータから取得できます。
トークンエンドポイントのURLを作成します。
認可コード等のパラメータを埋め込んでURLを作成します。
トークンエンドポイントに認可コードをPOSTして、IDトークンを取得する
const main = async () => {
await fetch(tokenEndpoint, {
method: "post",
headers: {
"Content-Type": "application/x-www-form-urlencoded"
}})
.then(response => {
return response.json();
})
.then(data => {
const idToken = data.id_token;
...
})
};
Code language: JavaScript (javascript)
fetchを使用して、先ほど作成したトークンエンドポイントURLにPOSTし、IDトークンを取得します。
トークンエンドポイントの要件で、ヘッダーは「application/x-www-form-urlencoded」を指定する必要があります。
IDトークンを使用してIDプールにアクセスし、一時的なクリデンシャルを取得する
この後の流れは前回と同様です。
const ssmClient = new SSMClient({
region: REGION,
credentials: fromCognitoIdentityPool({
client: new CognitoIdentityClient({ region: REGION }),
identityPoolId: IDENTITY_POOL_ID,
logins: {
[`cognito-idp.${REGION}.amazonaws.com/${USER_POOL_ID}`]: idToken
}
})
});
getParameter(ssmClient);
getName(idToken);
Code language: JavaScript (javascript)
IDトークンを使って、IDプールから一時的なクリデンシャルを取得します。
今回はSSMパラメータを取得することが目的ですので、SSMクライアントオブジェクトを作成後、パラメータストアにアクセスします。
加えて、IDトークンのクレームからユーザー名を取得する処理も行います。
環境構築
CloudFormationを使用して、本環境を構築し、実際の挙動を確認します。
CloudFormationスタックを作成し、スタック内のリソースを確認する
CloudFormationスタックを作成します。
スタックの作成および各スタックの確認方法については、以下のページをご確認ください。
各スタックのリソースを確認した結果、今回作成された主要リソースの情報は以下の通りです。
- バケット名:fa-035
- CognitoユーザープールのID:ap-northeast-1_27X20ZW00
- Cognitoユーザープール アプリクライアントのID:2c45u7pnk8ubba6vf4otnubncv
- Cognitoユーザープール ドメインプレフィックス:fa-035
- Cognito IDプールのID:ap-northeast-1:628252c8-3ed3-473d-9141-79bdf1cbd7ee
- SSMパラメータストアのパラメータ名:fa-035-authenticated
AWS Management Consoleからも、Cognitoの作成状況を確認します。
ユーザープールクライアントの「OAuth grant type」が「Authorization code grant」に設定されていることがわかります。
以上より、先述のホストされるUIによるサインイン/サインアウトページ用のURLは以下に定まります。
- サインインページ用URL:https://fa-035.auth.ap-northeast-1.amazoncognito.com/login?response_type=code&client_id=2c45u7pnk8ubba6vf4otnubncv&redirect_uri=https://s3-ap-northeast-1.amazonaws.com/fa-035/signin.html
- サインアウトページ用URL:https://fa-012.auth.ap-northeast-1.amazoncognito.com/logout?response_type=token&client_id=2c45u7pnk8ubba6vf4otnubncv&logout_uri=https://s3-ap-northeast-1.amazonaws.com/fa-035/signout.html
S3バケットにHTMLを設置する
S3バケットにHTMLを設置し、サインイン/サインアウト後のコンテンツを用意します。
先述のサインイン/サインアウト用URLをindex.htmlに記載後、AWS CLIを使用して設置します。
$ aws s3 cp ./html s3://fa-035/ --recursive
$ aws s3 cp main.js s3://fa-035
Code language: Bash (bash)
認証ユーザー向けコンテンツにアクセスする
準備が整いましたので、実際にホストされたUIにアクセスします。
以下のURLにアクセスします。
https://s3-ap-northeast-1.amazonaws.com/fa-035/index.html
するとルートページであるindex.htmlが表示されます。
「Sign In」を押下すると、サインインページが表示されます。
初回に限り、サインアップ処理を必要です。サインアップ処理に関しては、以下のページをご確認ください。
今回は「awstut」というユーザー名を登録します。
メールアドレスおよびパスワードを入力後、「Sign In」を押下します。
Implicit grantの時と同様に、ユーザー名とSSMパラメータストアの値が表示されました。
まとめ
OAuthフローがAuthorization code grantの場合でも、Cognitoトークンエンドポイントに認可コードをPOSTすることによって、トークンが取得できます。
そしてトークンを使ってIDプールにアクセスすることによって、一時的なクリデンシャルを取得することが可能で、これによってAWSリソースにアクセスが許可されます。