こんにちは、サイオステクノロジーの佐藤 陽です。
今回はEntraIDのトークン構成の設定に関する内容になります。
自分が開発を進めていく中で
「トークン構成の設定でオプション要求の追加したにもかかわらず、取得されたアクセストークンの中には設定した値が入っていない」
といったケースに遭遇しました。
こちらの問題点を解消する方法や、解決策に関わる知識部分をご紹介したいと思います。
はじめに
EntraID は IdP (Identity Provider) として、認証認可の仕組みを実現するために広く利用されています。
そしてEntraIDには、得られるアクセストークンやIDトークンの構成をカスタマイズできる機能があります。
この機能を利用し、とある情報をアクセストークンに含めようとしたのですが、トークンの構成を行ったにも関わらず、必要な情報が含まれないといった課題に直面しました。
そこで今回はこの原因と、原因を理解するための周辺知識について備忘録として書いていきたいと思います。
なお、今回の構成で利用する要素としては
- React/Nextjs
- MSAL(Microsoft Authentication Library)
- EntraID
といったものになります。
とはいえ、今日のお話はEntraID以外は特に環境に依存するものではありません。
トークン構成
EntraIDでアプリケーションを作成すると、Portal上において「トークン構成」といったブレードが見られます。
選択すると
- オプションの要求の追加
- グループ要求の追加
を行うことが可能となり、ここからトークンに含める追加情報を構成することができます。
例えば、オプション要求の追加を選択すると
- どのトークンに関する設定か
- どの要求を追加するか
を設定することができます。
今回は、試しに
対象トークン | 追加する要求 |
---|---|
アクセス | auth_time |
を設定し、アクセストークンの取得を試みます。
アクセストークンの取得
では実際にアクセストークンを取得します。
基本的はMSALのサンプルそのままを実行していきますので、詳細な実装は割愛します。
Config情報に関してはコチラを参考に、以下の内容で設定しました。
key | value |
---|---|
clientId | {EntraID上に登録したアプリケーションのクライアントID} |
authority | https://login.microsoftonline.com/ |
redirectUri | ローカルでの検証のため、ひとまず http://localhost:3000 |
scopes | User.Read |
また、併せてEntraID上のアプリケーションの認証の設定において
SPAのアプリケーションを追加し、リダイレクトURLをhttp://localhost
としておきます。
アクセストークン内容の確認
ではこの実装に基づくアプリケーションで取得したアクセストークンの内容をDecodeしたものを一部抜粋して掲載します。
{
"aud": "00000003-0000-0000-c000-000000000000",
"iss": "https://sts.windows.net/***/",
"iat": 1748319065,
"nbf": 1748319065,
"exp": 1748322980,
"acct": 1,
"acr": "1",
...(略)
"xms_ftd": "jjqoMQ6P8XOaNHnHHc-JnGBPyVrayvj9UXOQgTf1iL0BamFwYW5lYXN0LWRzbXM",
"xms_idrel": "5 16",
"xms_st": {
"sub": "EYjUyDvkYaYrC-pPaxE8jbp_imGQOGYEFIlRXjRG_mA"
},
"xms_tcdt": 1412690105
}
すると、この中に先ほど指定したはずのauth_time
の値が含まれていないことが確認できます。
なぜオプション項目が含まれていないのか
作成したアプリケーションのClientIDを正しく指定しているはずですし、設定が反映されていないのが腑に落ちません。
と、ここでDecodeした中身のaud
のパラメータに注目します。
このaudのパラメータですが定義としてはこちらに記載があります。
トークンの想定されている読者を識別します。 v2.0 トークンでは、この値は常に API のクライアント ID です。 v1.0 トークンでは、これは、クライアント ID、または要求で使用されるリソース URI になります。 値は、クライアントがトークンを要求した方法によって異なります。
(今回はv1.0)
現在、取得されたアクセストークンにおけるaud
の値は 00000003-0000-0000-c000-000000000000
です。
そしてこのaudの値はどのリソースURIを示しているかというと、以下に示したサイトから読み解くにMicrosoftGraphのAPIとなります。
- https://learn.microsoft.com/ja-jp/graph/permissions-reference
- https://learn.microsoft.com/ja-jp/entra/identity-platform/access-tokens
つまり、MicrosoftGraphのAPIを利用するために必要となるアクセストークンが、MicrosoftGraphのAPIを公開するアプリケーションマニフェストの情報に基づいて返されます。
マニフェストに関しては前回の記事でご紹介したので、こちらを参照ください。
繰り返しになりますが、audの値がMicrosoftGraphのURIの値になっているということは
そのAPIを公開するアプリケーションのマニフェストの内容に基づいてトークンの内容が決定され、返されます。
そのため、先ほど自ら設定したアプリケーションのアクセストークン構成はまったく意味を成しません。
なぜこのような状況が起きているかというと、MSALを利用する際にパラメータとして与えたScope
の設定が影響しています。
今回Scopeの設定としては、サンプルで使われていたUser.Read
をそのまま使ってしまっていました。
そしてこれは、MicrosoftGraphAPIのUser.Read
のScopeを指しています。
そのため、「このクライアントはMicrosoftGraphのAPIを利用したいんだな!」と判断されたため
MicrosoftGraphのAPIを管理するアプリのマニフェストに基づいてトークンが返されてしまったのです。
これを解決するためには、自らAPIを公開し、そのAPIを利用するためのアクセストークンを発行する必要があります。
以下に実際のステップを記載します。
再取得(意図したクレームを含める方法)
API の公開設定
先ほどのアプリケーションにおいて新規にAPIの公開を行います。
- アプリケーションURIの発行
- Scopeの追加
Scopeに関しては以下のような内容で追加します。
値としては好きなものを入力してください。
Scope の指定
MSALでアクセスする際に、今回追加したScope(api://cb769b13-3f44-41ad-abcf-444acca396af/Option.Read
)にScopeを置き換えます。
こうすることで、先ほど公開したAPIにアクセスするためのアクセストークンが取得できるようになります。
export const loginRequest = {
scopes: ["api://cb769b13-3f44-41ad-abcf-444acca396af/Option.Read"],
};
ここまでできれば準備OKです。
トークン内容の確認
再度アクセストークンを取得し、デコードします。
{
"aud": "api://cb769b13-3f44-41ad-abcf-444acca396af",
"iss": "https://sts.windows.net/***/",
"iat": 1748333202,
"nbf": 1748333202,
"exp": 1748338754,
"acr": "1",
"aio": "AVQAq/8ZAAAAn3CcIgjMLmAO1FwB+2ivXeaausYBhcFitnPXL1vI7N3fh63o7WnB0jK6mH/rdhjZxTfVuRvymlC6tzAhB1disVqX7l9OhDHPF+s/qSneArw=",
"amr": [
"pwd"
],
"appid": "cb769b13-3f44-41ad-abcf-444acca396af",
"appidacr": "0",
"auth_time": 1748333497,
"email": "ak-sato@sios.com",
"idp": "https://sts.windows.net/47d0c615-90e7-43ad-8653-720c7bf26547/",
"ipaddr": "123.1.7.105",
"name": "佐藤 陽",
"oid": "b00dbe40-3b3d-46ec-962a-4abba930da7d",
"rh": "1.AVMA7zxCzECqM0S84dL_kXbAyhObdstEP61Bq89ESsyjlq9TAJlTAA.",
"scp": "Option.Read",
...(略)
}
するとまず、auth_time
の値が正しく取得できていることが確認できました。めでたし!
また、aud
の値に関しても先ほど作成したアプリケーションURIの値になっていることが分かります。
この点から、自ら作成したアプリケーションのトークン構成に紐づいてアクセストークンが返されていることがわかります。
これまでの流れを概念図に示すと以下のようになります。
- Scopeとして何を指定するか
- audの値はどのAPIのIDとなっているか
- どのアプリケーションマニフェストに基づいてトークンが返ってきてるか
などを意識することが重要であると考えました。
IDTokenの場合は?
なお、IDトークンに関しては特にこういった設定を行わなくてもトークンの構成の設定は反映されます。
これはIDトークンの性質を考えれば分かりますが、IDTokenはAPIのアクセスに利用されるものではないためです。
そのためAPIに関わる設定に依らず、アプリケーション自体の設定に依存するため、今回のようなAPIの設定は不要となります。
まとめ
今回は、アクセストークンに自ら指定したオプション要求が含まれていない課題の解決方法および、その周辺知識の紹介を行いました。
aud
のパラメータの定義- アプリケーションマニフェストの考え方
- アクセストークン・IDトークンの役割
などがしっかり理解できていればすぐ分かることでしたが、なかなかそこに気づけず時間を溶かしてしまいました。
このあたりまだまだ理解が不十分なところもあるのでしっかり抑えていきたいと思います。
ではまた!