OpenID Connect 1.0 Relying Party を実装するための Haskell 用ライブラリ

タイトルの通り,OpenID Connect 1.0 のクライアントライブラリを作りました.Hackage に上げてありますので cabal install で導入できます.

背景

Web サービスを作成するにあたって認証をどうするかは悩ましいところです.先々の展望を考慮して自前で実装することもありますが,小規模あるいは個人サービスであれば外部の認証サービスを利用することが選択肢に入るはずです.

あるサービスを実装するにあたり GoogleOpenID Provider (以降 OP) として利用しようと考えたのですが,OpenID Connect 1.0 に対応したパッケージが見当たらなかった (2015 年 7 - 8 月ぐらいのことです) ため,今回のライブラリを作成しました.

現在サポートしているのは Code Flow のみです.

利用方法

手順としては以下の通りです.

  1. discover で OP の情報 (Provider) を取得
  2. Provider とクレデンシャルから OIDC を作成
  3. Authentication Request URL を作成 (してリダイレクト)
  4. OP からのコールバックを受けてトークンを要求,かつ受け取ったトークンを検証
  5. 検証済みトークンをサービスで利用する

実際に実行可能なコードが リポジトリ の examples にあります.

API の簡単な紹介

まずは discover で OP の情報 (Provider) を取得します.

discover
    :: IssuerLocation
    -> Manager
    -> IO Provider
discover location manager = do
    ...

Web.OIDC.Discovery.Issuers に具体的な Issuer Location の値を定義しています.Managerhttp-client パッケージのものです.Code Flow では TLS 必須ですから http-client-tls の設定を使って Manager を生成する必要があります.

次に OIDC を準備します.

newOIDC :: CPRG g => IORef g -> OIDC
newOIDC ref = def { cprgRef = Ref ref }

CPRGcrypto-random に定義されている暗号論的擬似乱数生成器の class です.暗号論的擬似乱数生成器はほぼ間違いなく使うでしょうから,引数にはそれを指定します. 指定された引数は ID Token Validation の際に id_token (JWT) のデコード処理で使用します.デコード処理では jose-jwt を利用しています.

あとは setProvidersetCredentials を使用して,先に取得した Provider や client ID/secret 等を設定します.

次に authorization endpoint にリクエストするための URL を取得します.

getAuthenticationRequestUrl
    :: (MonadThrow m, MonadCatch m)
    => OIDC
    -> Scope
    -> Maybe State
    -> Parameters
    -> m URI
getAuthenticationRequestUrl oidc scope state params = do
    ...

第 2 引数は OpenID Connect 1.0 仕様の scope パラメータに相当します.このパラメータに対する openid の指定は MUST であるため,明示的に指定しなくても内部で補完しています. 第 3 引数は state パラメータ (RECOMMENDED) に指定する値です.MUST ではないため Maybe としています. 第 4 引数は OPTIONAL なパラメータを指定するリストです.

ユーザの許可を得てコールバックされたら,token endpoint に ID Token とアクセストークンを要求します.

requestTokens
    :: OIDC
    -> Code
    -> Manager
    -> IO Tokens
requestTokens oidc code manager = do
    ...

Code は authorization endpoint から渡された code パラメータの値です.

結果として得られる Tokens には検証済みの ID Token が含まれていますので,これをサービスで利用します.またユーザ情報を取得する場合は Tokens に含まれるアクセストークンを利用します.