Azure AD B2CをPHPと使う (2) SPAから送られてきたトークンを検証する

SPAから送られてきたトークンを検証する

Azure AD B2Cと連携するのにあたり、PHP側のタスクは、

  • 適切なAPI
  • ページの送出

にあろうかと思います。

Azure AD B2Cとの連携という意味では、APIにおいてアクセスしてきたユーザーが適切なトークンを持っているか、つまり、認証を経て当該アクセスをする正当な権限を持っていることを検証することに尽きます。具体的には、IDを保証するトークンと権限を保証するトークンということになるでしょう。

現状でそういったサンプルは見かけないのですが、要件としては、以下のドキュメントとOpenIDのドキュメントを参考に、

トークンの概要 - Azure Active Directory B2C | Microsoft Docs

 

  • 対象ユーザー
  • 期間の開始時刻 および 期限切れ日時
  • 発行者
  • nonce

 

これらを検証することになるでしょう。

トークンには、認証結果を示すIDトークンと承認結果を示すアクセストークンがあり、それぞれ、もしくは、IDトークンのみを検証して、サーバー内でアクセスコントロールを行うか、B2C側に許可情報を付与してアクセストークンも検証することになると思います。せっかく認証機構を外だしするわけですから、アクセストークンもB2Cで管理した方がいいと思いますが、既存のCMSなどと連携する際はIDトークンのみの検証になることも考えられます。

docs.microsoft.com

docs.microsoft.com

 

2015年頃にPHPサンプルがMicrosoftのブログで閲覧できていたのですが、現状は404 not foundになっています。おそらく、out-datedなのでしょう。

その404ページに貼られていたリンクですが、Azure ADのトークン関係で、重要そうなのでメモっておきます。

プライマリ更新トークン (PRT) と Azure AD - Azure Active Directory | Microsoft Docs

 

ところで、当時の仕様通りかどうかはわからないのですが、大きく変更がないとすれば、(というか動いてほしいですが、)当時のサンプルでのフローを追ってみます。

 

トークンの概要 - Azure Active Directory B2C | Microsoft Docs

Azure AD B2C には、OpenID Connect メタデータ エンドポイントがあります。 このエンドポイントを使用すると、アプリケーションは実行時に Azure AD B2C に関する情報を要求できます。 この情報には、エンドポイント、トークンの内容、トークンの署名キーが含まれます。 Azure AD B2C テナントには、ポリシー別の JSON メタデータ ドキュメントが含まれています。 メタデータ ドキュメントは、いくつかの便利な情報が含まれている JSON オブジェクトです。 メタデータには、トークンの署名に使用される公開キーのセットの場所を示す jwks_uri が含まれます。 次に示すのがその場所ですが、メタデータ ドキュメントを使用して jwks_uri を解析することにより、その場所を動的にフェッチするのが最善の方法です。
https://contoso.b2clogin.com/contoso.onmicrosoft.com/b2c_1_signupsignin1/discovery/v2.0/keys

この URL にある JSON ドキュメントには、特定の時点で使用されているすべての公開キー情報が含まれています。 アプリでは、JWT ヘッダーの kid 要求を使用して、特定のトークンの署名に使用される JSON ドキュメント内の公開キーを選択できます。 その後、正しい公開キーと指定されたアルゴリズムを使用して、署名の検証を実行できます。

 つまり、2020年現在のキーの取得は、以下から取得せよとのことです。

https://[テナントID].b2clogin.com/[ディレクトリID]/[ポリシー]/discovery/v2.0/keys

ところで、以前の仕様だと、ポリシーはパスではなく、クエリで?p=で指定していました。

まず、ここからキーを取得しておき、次に、アクセスしてきたauthorizationHeaderから、Bearer を見つけ、値を取り出してjwtとして処理していくという流れですね。

nbf exp aud などを検証したあと、先ほどエンドポイントから取得したkeysの中から使用するキーを選択し、それに該当するパブリックキーで、送られてきたトークンをopenssl_verifyで、検証するという形でした。

 

実際に、これで検証できるかどうか、これから試してみようと思います。