SPA+Backend構成なWebアプリへのOIDC適用パターン

ritouです。

マシュマロでSPA+BE構成のWebアプリでOAuthやOIDCしたい!って話をよくいただきます。

最近だと、こんな質問がありました。

OIDCから発行されたトークンの取り扱いについて質問させてください。 SPA +OIDC(認可コードフロー)構成によるWEBアプリケーションの開発を考えています。 idPによる認証後、バックエンドとフロントエンドのAPI通信に使うべきはIDトークンとアクセストークンだとどちらになるのでしょうか?

SPAだろうがMPAだろうがネイティブアプリだろうが、

  • IDToken: RP(Client)がログイン機能に利用するために利用
  • AccessToken: RP(Client)がRSに対してリソースアクセスをする際に利用

という原則は変わりません。これを捻じ曲げるような利用方法をするならば標準化仕様としての話は一旦終わり、後は独自実装としてリスク受容して頑張ってくださいとなります。

ではなぜ最初の質問のような混乱に至るのか、今回はOIDCをどの部分に適用するかという観点で整理すると2つの実装パターンがあります。

1. SPA+BE自体は独自、ID連携する部分にOIDCを適用

まずは普通にSPA+BE構成でアプリケーションを作る場合を考えてみましょう。

ソーシャルログインなどを使わない場合、SPAはBEのログインAPIみたいなのを叩きつつ、ユーザーと対話しつつでログインさせます。

ログイン成功後は、CookieなりSessionTokenなりを用いてBEにアクセスするでしょう。

これ別にOIDC適用しなくても実装できると思います。SPAがユーザー認証を扱う分だけ、この部分にはOIDCを適用しにくいとも言えます。 お好きなフレームワークの枯れた認証機能を使って作ったらいいでしょう。

このようなWebアプリが存在する状態でGoogleログインなどを実装する場合、OIDCのトークンの流れはどうなるでしょうか?

IdPからなんらかの方法でIDTokenとアクセストークンがもらえます。 そして、IDTokenはすぐにBEで検証されてログイン処理に利用されます。

ではAccessTokenはどう使われるかというと、SPAもしくはBEからのリソースアクセスに利用されます。

SNSアカウントの最新のプロフィール情報を取得するぐらいであれば、FEからのリソースアクセスもあり得るでしょう。 決済機能などであればBEからのリソースアクセスとなるでしょう。

IdPからのIDTokenやAccessTokenの基本の使い方はこんな感じです。

整理すると登場人物は

  • IdP, RS: Googleみたいなところ
  • RP(Client): SPA+BE一体化したもの

トークンの用途は

  • IDToken: RP(Client)はログイン処理に利用
  • AccessToken: RP(Client)がRSにリソースアクセスする時に利用

という感じです。

2. BEがRSとなる場合

混乱の原因として考えられるのは、BEがRSとなるケース があるためです。

先ほどと登場人物が結構変わりますね。

  • IdP: Webアプリ
  • RP(Client): IdPとは疎結合になっているWebアプリで、認証状態はSPA単体で管理
  • RS: BEはログイン後のリソースアクセスに利用

SPAはIDTokenを受け取ったら検証して、メタデータなどをセッションに保存しておきます。セッション管理をSPAだけで行うという感じです。 その結果、BEはログインセッションの管理などしなくてもよくて、AccessTokenを受け取ってリソースを返したらOKとなります。 SPAとBEの間のやり取りで使われるのはIdPから受け取ったAccessTokenでしょう。 BEはRSな訳なので、なんとか(JWTやIdPが提供するトークンイントロスペクションエンドポイントを利用)してAccessTokenを検証して適切なリソースを返します。

これどこかでみたことありませんか? SPAがJS SDKの機能を使うだけでログインできて、トークンももらえる。バックエンドはRSとして振る舞う。 まさにAuth0とかのユースケースです。

少し細かいとこ見ちゃうと、OIDCの処理を行った時点ではIdPとステータスが同期するわけですが、それ以降は同期されません。ただ、Webアプリで同期する必要があるケースもあります。グループ企業の名前のついたIDを扱うWebアプリ群でSSO的に振る舞わなければならない場合、定期的にユーザーのログイン状態の同期をかけたり、しれっとユーザーインタラクションのない認証フローを走らせたりするする必要があるわけです。標準化仕様で言うとOpenID Connect Session ManagementとかNative AppだとNative SSOみたいな仕様が使えるわけですが、 Auth0とかは自前でその辺りをよしなにできるようにして自分たちの管理するIdPとのログイン状態の同期を実現している わけです。

まとめ

SPA+BE構成のWebアプリにOIDCを適用する2パターンについて紹介しました。 最初に紹介した質問に対する私の回答は「2つ目を意識して混乱してそうだけどやってることは1っぽいよね。だったらIdPから受け取ったIDTokenもAccessTokenも使わずに自前のセッションでなんとかしたらいいんじゃない?」と言う感じです。

ここまでで紹介した1, 2の実装パターンは どちらもありえる、そんだけだ それぞれ有用なものであり、実際に多く使わているのですが、混ぜるな危険 なわけです。

まずは自分が考えるOIDC適用がどっちなのかを考えてみましょう。そうすれば、実装する内容も決まってきます。

それでも迷ったら質問してください。

marshmallow-qa.com

ではまた。