🛡️

Remix AuthのOpenID Connect対応ストラテジを作った

2024/06/09に公開

はじめに

RemixというReactをベースにしたWebフレームワークにおいて認証機能を入れたい時には、Remix Authと呼ばれるライブラリを使うと簡単にできるようです。Remix Authはストラテジパターンで拡張できるため様々な派生ライブラリがあります(代表的なものだとRemix Auth OAuth2)が、きちんとOpenID Connect対応した拡張がなかったので作りました。
https://github.com/manaty226/remix-auth-openid

なぜ作ったのか

前述したようにRemix Authを拡張したライブラリがいくつかあり、Remix Auth OAuth2をベースにしたOpenID Connect対応を謳うライブラリも存在しました。しかし、ソースを読んでみると単にscopeにopenidを追加しただけでnonceパラメータを使っておらず、トークンレスポンスで返ってきたIDトークンを確認せずアクセストークンを使って/userinfoエンドポイントにアクセスしてユーザー情報を取り、その情報を丸呑みして認証するような所謂OAuth認証[1]になっていたので、ちゃんとOpenID Connectに対応した拡張を作りました。

どうやって作ったか

IdPを作るよりRPを作る方がはるかに簡単とはいえ、一からパラメータをパースしたりOAuthやOIDCの膨大な仕様を誤りなく実装しきるのは時間がかかるし難しいので、node-openid-clientを使って対応しました。こちらのライブラリはOpenID FoundationのCertificationもとっているので安全安心に利用することができます(利用方法を誤らなければ)。
https://github.com/panva/node-openid-client

Remix Authストラテジの実装

Remix Authストラテジは、公開されているStrategyを継承したクラスを作り、そこにauthenticateメソッドを実装すれば、利用者がauthenticator.use(strategy, "strategy-name")`というシグネチャで簡単に利用することができます。Remix Auth OAuth2で実装されている認可コードフローの流れを踏まえながら、nonceパラメータを追加したりIDトークンのチェック項目を拡張できるようにしたりしつつ、node-openid-clientを使ってリクエストを組み立てていけば100行くらいで実装することができました。

https://github.com/manaty226/remix-auth-openid/blob/f7567c9a9eea71d24de2ee8a5edef1066cff3a52/src/index.ts#L82-L174

実装したRemix Authの利用

実装したストラテジを実際に利用できるか、簡単なサンプルアプリを作って確かめました。
https://github.com/manaty226/remix-auth-openid-example

Remix Authのインターフェースに則っているので、以下のようなコードを書くだけでアプリから非常に簡単に利用することができます。手元でKeycloakを動かして実際にログインして、トークン類も取得できることを確認しました。
https://github.com/manaty226/remix-auth-openid-example/blob/46fe739ddfe3740aa4cf608235a0703967a3c4c4/app/modules/auth/auth.server.ts#L13-L38

おわりに

とりあえず認可コードフローが動くRPであれば既存のライブラリを使いながら簡単に作れるよなというのが改めての感想でした。Remix Authがサーバーサイドで動くWebアプリの認証ソリューションなのでハイブリッドフローなど認可コードフロー以外のフローに対応する必要もない気がしますし、ほとんどnode-openid-clientに丸投げしているラッパーみたいなストラテジになったので、自分で仕様対応しないといけないことも現時点で見つけられてないのですが、最近ドラフトから晴れてRFCになったDPoPを使えるのか等は色々と試したい気持ちがあります。
あと、某IdPはクライアントID/シークレット方式のクライアント認証と他の認証方式(JWTベアラーなど)の応答時間の差がものすごく大きいので、そうしたクライアント認証方式のバリエーションは試してみたい。

脚注
  1. 元のRemix Auth OAuth2が認可コードフロー+PKCEを前提としているので、よく考えるとOAuth認証で懸念される認可コード横どり攻撃やアクセストークン置換攻撃への耐性はあります。しかし、それは単にOAuthをできるだけ安全に利用しているにすぎず、OpenID Connectに対応しているわけではない(例えばIDトークンを見ていないのでmax_ageのような認証結果の連携ができない)ため、そうしたライブラリがRemix Auth OIDCみたいな冠をつけているのは誤っていると考えています。 ↩︎

Discussion