OpenID Connect 1.0 Relying Party を実装するための Haskell 用ライブラリ
タイトルの通り,OpenID Connect 1.0 のクライアントライブラリを作りました.Hackage に上げてありますので cabal install
で導入できます.
背景
Web サービスを作成するにあたって認証をどうするかは悩ましいところです.先々の展望を考慮して自前で実装することもありますが,小規模あるいは個人サービスであれば外部の認証サービスを利用することが選択肢に入るはずです.
あるサービスを実装するにあたり Google を OpenID Provider (以降 OP) として利用しようと考えたのですが,OpenID Connect 1.0 に対応したパッケージが見当たらなかった (2015 年 7 - 8 月ぐらいのことです) ため,今回のライブラリを作成しました.
現在サポートしているのは Code Flow のみです.
利用方法
手順としては以下の通りです.
discover
で OP の情報 (Provider
) を取得Provider
とクレデンシャルからOIDC
を作成- Authentication Request URL を作成 (してリダイレクト)
- OP からのコールバックを受けてトークンを要求,かつ受け取ったトークンを検証
- 検証済みトークンをサービスで利用する
実際に実行可能なコードが リポジトリ の examples にあります.
API の簡単な紹介
まずは discover
で OP の情報 (Provider
) を取得します.
discover :: IssuerLocation -> Manager -> IO Provider discover location manager = do ...
Web.OIDC.Discovery.Issuers
に具体的な Issuer Location の値を定義しています.Manager
は http-client パッケージのものです.Code Flow では TLS 必須ですから http-client-tls の設定を使って Manager
を生成する必要があります.
次に OIDC
を準備します.
newOIDC :: CPRG g => IORef g -> OIDC newOIDC ref = def { cprgRef = Ref ref }
CPRG
は crypto-random に定義されている暗号論的擬似乱数生成器の class です.暗号論的擬似乱数生成器はほぼ間違いなく使うでしょうから,引数にはそれを指定します.
指定された引数は ID Token Validation の際に id_token
(JWT) のデコード処理で使用します.デコード処理では jose-jwt を利用しています.
あとは setProvider
や setCredentials
を使用して,先に取得した 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
に含まれるアクセストークンを利用します.