前回使用したアプリケーションを使用して認可コードフローを見ていきます。
TOC
概要
今回のフローをシーケンス図にすると以下のとおりです。
- ブラウザでログインボタンをクリック
- アプリケーションは認可エンドポイント(AzureAD)に対してユーザーをリダイレクト
- AzureADとのユーザーセッションがない場合には、AzureADがログイン画面を返します
- ユーザーがユーザーネーム、パスワード、追加認証をAzureADと行う
- AzureADはユーザーの認証が完了すると、HTTPのリダイレクトを利用して認可コードをアプリケーションに通知
- アプリケーションが認可コードを用いてトークンの取得
- アクセストークンを用いてユーザー情報を取得
認可コードフローの始まり
認可コードフローを始めるため、ユーザーを認可エンドポイントにリダイレクトします。その、認可エンドポイントは、openidメタデータに含まれているので、見てみましょう。
AzureADのOpenId メタデータは下記のURLのとおりです。
https://login.microsoftonline.com/<tenant id>/v2.0/.well-known/openid-configuration
上記にアクセスするとjson形式でメタデータが取得できます。
{
"token_endpoint": "https://login.microsoftonline.com/<tenant id>/oauth2/v2.0/token",
"token_endpoint_auth_methods_supported": [
"client_secret_post",
"private_key_jwt",
"client_secret_basic"
],
"jwks_uri": "https://login.microsoftonline.com/<tenant id>/discovery/v2.0/keys",
"response_modes_supported": [
"query",
"fragment",
"form_post"
],
"subject_types_supported": [
"pairwise"
],
"id_token_signing_alg_values_supported": [
"RS256"
],
"response_types_supported": [
"code",
"id_token",
"code id_token",
"id_token token"
],
"scopes_supported": [
"openid",
"profile",
"email",
"offline_access"
],
"issuer": "https://login.microsoftonline.com/<tenant id>/v2.0",
"request_uri_parameter_supported": false,
"userinfo_endpoint": "https://graph.microsoft.com/oidc/userinfo",
"authorization_endpoint": "https://login.microsoftonline.com/<tenant id>/oauth2/v2.0/authorize",
"device_authorization_endpoint": "https://login.microsoftonline.com/<tenant id>/oauth2/v2.0/devicecode",
"http_logout_supported": true,
"frontchannel_logout_supported": true,
"end_session_endpoint": "https://login.microsoftonline.com/<tenant id>/oauth2/v2.0/logout",
"claims_supported": [
"sub",
"iss",
"cloud_instance_name",
"cloud_instance_host_name",
"cloud_graph_host_name",
"msgraph_host",
"aud",
"exp",
"iat",
"auth_time",
"acr",
"nonce",
"preferred_username",
"name",
"tid",
"ver",
"at_hash",
"c_hash",
"email"
],
"kerberos_endpoint": "https://login.microsoftonline.com/<tenant id>/kerberos",
"tenant_region_scope": "AS",
"cloud_instance_name": "microsoftonline.com",
"cloud_graph_host_name": "graph.windows.net",
"msgraph_host": "graph.microsoft.com",
"rbac_url": "https://pas.windows.net"
}
ここにあるauthorization_endpoint
が認可エンドポイントとなり、必要なパラメーターを送ることにより、フローが開始されます。
実際のリクエストは下記のようなものになり、
https://login.microsoftonline.com/<tenant id>/oauth2/v2.0/authorize?client_id=8dfe5f8d-a220-466e-805b-9685214cbf33&redirect_uri=http://localhost:4200&response_type=code&scope=openid profile email&nonce=0499a2cc83e1e6f1e634e8e7effb6ca35aJSvNqob&state=92a722d4e4f454b5dac1adac37ed231838wXEc2Cq&code_challenge=jmDqnzzBFUhntJ0WlHWCT6WbAYw8ZqPYzjL61hu2T9w&code_challenge_method=S256
含まれているクエリは
- client_id
- redirect_uri
- response_type
- scope
- nonce
- state
- code_challenge
- code_challenge_method
になります。各パラメータの説明は下記に任せますが、基本的には必須+セキュリティに関するオプション(state, code_challenge, code_challenge_method)が含まれてます。
参考 Microsoft ID プラットフォームと OAuth 2.0 認証コード フローこのリクエストの返答として、セッションがなければログイン画面が返されます。
認可コードの発行とリダイレクト
ユーザーの認証が完了すると、認可コードをクエリに含めリダイレクトすることでアプリケーションにコードを渡します。
リダイレクト先は下記のようになります。
http://localhost:4200/?code=0.AXAACLwE9mlzp02q2MWUtf6DXo1f_o0gom5GgFuWhSFMvzNwAAA.AQABAAIAAAD--DLA3VO7QrddgJg7WevrN-0krPS0GiI5nnZ9sbDVlZ_E5aOx8AqJwiNVFQu_hPYdZsMDqJ1WlRM4EYT53kK8ERjyL53v0ZJiyurV0Hvy85UAv0D7mJzQImMaPnVcnneldJLhjlfU0y6SOS9VMNw8-dTiMFbEkhU2I9j2wTWBFZDBwZRRns6ST9ntqCPaEd2KxGYOp2lJfPt_VoJfdpJ1Lf5dlgrtqRcWleyzSPE7aXXwxGubtBugv9byYCYCvwsP7QLRIVEIKl6hZERwU5mUINme_GQYe2gb6QdUXNOl2rdQk3ZmRyz5NxlFRp4eE1ru_Xskrv_JiA0fWlmgfE0R0NDA5p-FzCzWV4NmZSx_yA6DXROQl37QiAgNq077oCUqDJl7UZTgPHcbmXkNUCOC1IzSnz1XDbox-LbS6Z9TNkH0a6-wrLuN8SUBNC9GwAFEa_bfWNNP-3J0c9xKJsTZNttELQZNpZ2Cj2yLijJRl3Nwmtj4dVTOWNgiJi0e4osxs9XAYr6HutXo_itrmw32qM49CBvMv4BHTFoFH4hUZoahH1fuVKSxFck0vc1pY2UHhr6HAp1sQ2_TfIMFvTDdwv4N_ANZlb9UpSx1hl6k26pBVxDSSKrcfrzx0uYg1Aqywu37wLP605VN9D0Jau2eWU0y_l1uGouYF9HKbVXlKeU6tj1jz-aJOGHtIK4smHNQCOawGJurduD4aAm1gpaBB8ixEKmWMWVT8y1F3UJmWiAA&state=92a722d4e4f454b5dac1adac37ed231838wXEc2Cq&session_state=0990b5a3-f67b-488c-9317-82462fe3128d
含まれるパラメーターは
- code
- state
- session_state
になります。
codeは次のトークンエンドポイントに対してトークンと交換するための短時間有効なコードです。stateは、認可エンドポイントに対して投げたものと同じものと返すような仕様です。session_stateといったパラメータも返ってきていますが、特に内容に規定はないため気にする必要はありません。
トークンエンドポイント
リダイレクト先にアクセスすると、アプリケーションがcodeを受け取りトークンエンドポイントにリクエストを行います。
URL
https://login.microsoftonline.com/<tenant id>/oauth2/v2.0/token
フォームデータ
- grant_type: authorization_code
- client_id: 8dfe5f8d-a220-466e-805b-9685214cbf33
- code_verifier: a1025ad6e051340c86e08633605f4ec6194989bb4f1daeea338d7269c9ceSSSrsIP
- code: 0.AXAACLwE9mlzp02q2MWUtf6DXo1f_o0gom5GgFuWhSFMvzNwAAA.AQABAAIAAAD–DLA3VO7QrddgJg7WevrN-0krPS0GiI5nnZ9sbDVlZ_E5aOx8AqJwiNVFQu_hPYdZsMDqJ1WlRM4EYT53kK8ERjyL53v0ZJiyurV0Hvy85UAv0D7mJzQImMaPnVcnneldJLhjlfU0y6SOS9VMNw8-dTiMFbEkhU2I9j2wTWBFZDBwZRRns6ST9ntqCPaEd2KxGYOp2lJfPt_VoJfdpJ1Lf5dlgrtqRcWleyzSPE7aXXwxGubtBugv9byYCYCvwsP7QLRIVEIKl6hZERwU5mUINme_GQYe2gb6QdUXNOl2rdQk3ZmRyz5NxlFRp4eE1ru_Xskrv_JiA0fWlmgfE0R0NDA5p-FzCzWV4NmZSx_yA6DXROQl37QiAgNq077oCUqDJl7UZTgPHcbmXkNUCOC1IzSnz1XDbox-LbS6Z9TNkH0a6-wrLuN8SUBNC9GwAFEa_bfWNNP-3J0c9xKJsTZNttELQZNpZ2Cj2yLijJRl3Nwmtj4dVTOWNgiJi0e4osxs9XAYr6HutXo_itrmw32qM49CBvMv4BHTFoFH4hUZoahH1fuVKSxFck0vc1pY2UHhr6HAp1sQ2_TfIMFvTDdwv4N_ANZlb9UpSx1hl6k26pBVxDSSKrcfrzx0uYg1Aqywu37wLP605VN9D0Jau2eWU0y_l1uGouYF9HKbVXlKeU6tj1jz-aJOGHtIK4smHNQCOawGJurduD4aAm1gpaBB8ixEKmWMWVT8y1F3UJmWiAA
- redirect_uri: http://localhost:4200
となり、必須パラメータ(grant_type, client_id, code, redirect_uri)とセキュリティ用PKCEパラメータ(code_verifier)がフォームデータとして送られています。
AzureAD側でコードが有効であると判断されると、返答にアクセストークンとIDトークンが返されます。
{
"token_type": "Bearer",
"scope": "openid profile email",
"expires_in": 3875,
"ext_expires_in": 3875,
"access_token": "<access token>",
"refresh_token": "<refresh token>",
"id_token": "<id token>"
}
基本的には、認可コードフローはこれで終了です。
このあとアクセストークンを利用して、リソースへのアクセスが行われます。
リソース(ユーザー情報)の取得
アクセストークン取得後、リソースを取得する流れを見ます。
先程のトークンエンドポイントで得たデータに、token_type
がBearerとあるので、Bearerとしてアクセストークンを渡してリソースを取得します。
今回の例は、userinfoのエンドポイントに対して、リクエストをなげます。
https://graph.microsoft.com/oidc/userinfo
そして、Authorizationヘッダーにアクセストークンをいれこみます。
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJub25jZSI6Ik5TRTQzNjZkX1oyZEJINXZiUFUzMUV2UHdEck5NazFYaW1QZnNXVW5SYTAiLCJhbGciOiJSUzI1NiIsIng1dCI6ImpTMVhvMU9XRGpfNTJ2YndHTmd2UU8yVnpNYyIsImtpZCI6ImpTMVhvMU9XRGpfNTJ2YndHTmd2UU8yVnpNYyJ9.eyJhdWQiOiIwMDAwMDAwMy0wMDAwLTAwMDAtYzAwMC0wMDAwMDAwMDAwMDAiLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC9mNjA0YmMwOC03MzY5LTRkYTctYWFkOC1jNTk0YjVmZTgzNWUvIiwiaWF0IjoxNjUxNTY0NzQ1LCJuYmYiOjE2NTE1NjQ3NDUsImV4cCI6MTY1MTU2ODkyMSwiYWNjdCI6MCwiYWNyIjoiMSIsImFpbyI6IkUyWmdZTWhaVXhlWWtPWGo3TE4xSHZNMzZaakdYeXZOcFVvK1pyWHNMVjN4ZllIcGVpWUEiLCJhbXIiOlsicHdkIl0sImFwcF9kaXNwbGF5bmFtZSI6Im9pZGMtZnJvbnRlbmQiLCJhcHBpZCI6IjhkZmU1ZjhkLWEyMjAtNDY2ZS04MDViLTk2ODUyMTRjYmYzMyIsImFwcGlkYWNyIjoiMCIsImZhbWlseV9uYW1lIjoiVGVzdCIsImdpdmVuX25hbWUiOiJVc2VyIiwiaWR0eXAiOiJ1c2VyIiwiaXBhZGRyIjoiMTExLjEwMi4xOTQuMTYxIiwibmFtZSI6IlRlc3QgVXNlciIsIm9pZCI6IjkxYmY5OGNmLTEwMDEtNDk3Mi1iYWQ4LWI1YjY3YTBlZjZjZiIsInBsYXRmIjoiMyIsInB1aWQiOiIxMDAzMjAwMUU5RUFDMjRFIiwicmgiOiIwLkFYQUFDTHdFOW1senAwMnEyTVdVdGY2RFhnTUFBQUFBQUFBQXdBQUFBQUFBQUFCd0FHUS4iLCJzY3AiOiJvcGVuaWQgcHJvZmlsZSBlbWFpbCIsInNpZ25pbl9zdGF0ZSI6WyJrbXNpIl0sInN1YiI6IkN1cFRlWWlldlIyTEJidVFKT2hMM1g1b1U5OXJmOTVlVWpNWm9FbzZINjQiLCJ0ZW5hbnRfcmVnaW9uX3Njb3BlIjoiQVMiLCJ0aWQiOiJmNjA0YmMwOC03MzY5LTRkYTctYWFkOC1jNTk0YjVmZTgzNWUiLCJ1bmlxdWVfbmFtZSI6InRlc3R1c2VyQHl0c3Uub25taWNyb3NvZnQuY29tIiwidXBuIjoidGVzdHVzZXJAeXRzdS5vbm1pY3Jvc29mdC5jb20iLCJ1dGkiOiJLaWRYaGM4cUVrbXpkSDJWMUI0Q0FBIiwidmVyIjoiMS4wIiwid2lkcyI6WyJiNzlmYmY0ZC0zZWY5LTQ2ODktODE0My03NmIxOTRlODU1MDkiXSwieG1zX3N0Ijp7InN1YiI6IjlXNExWUVltcHpHbmRPcC0yVXhZUGNtVTBqVktVdjV0NzRQdG9zOFdnQ1UifSwieG1zX3RjZHQiOjE2MjY2ODUwODd9.RmgvwHufb5NRylbKcB1G_5wfjfojROSoF-Y9XGgQZaFYmCKCPeWrs0fNTomveiHxawJ2-PDZKCqnbLBJoux8GusGx0zLQWSOoHCOPhjIMaFxXRdysn9HCBvR5xzgT6n98CdYhcrFpRlyj8rvmfxAuf7s7VOITjWtO1qjUHYeZQ4UUU7T74aZqsX-6ID7eedt8REXVxG3gGA56FLtAuvCT-D5u2ei6CgsnmDhWxQezz_KQ3aAYyzMMyUlVYYzy-TxM8xENJfEQ8Wn8Z7iKViub45wKQyVQH2Bgt97Cd1REHwHHCU2S98NQl9Gj0NUL6HRmubmd68wpJJaxYPmxi77pg
アクセストークンが検証され、有効と判断された場合にはユーザー情報が帰ってきます。
まとめ
AzureADとの認可コードフローをざっくり見てみました。基本的には、どのIDPを使用しても同様のフローになります。ただ、ユーザー認証周りはIDPとのポリシーに依存するのでMFAを行ったり、場合によっては外部のIDPにルーティングされる場合もあります。