Digital Identity技術勉強会 #iddance 7日目の記事です。
ID Stackを手掛けるORYの最新作、ORY Kratosを触ってみたので、どんな感じで使えそうか書いていきます。
なお、執筆時点でのバージョンは v0.8.0-alpha.3 です。
ORY Kratosとは
ユーザ管理と認証を実装しているヘッドレスなIDサーバのOSSです。
実装されている主な機能としては以下です。
- ログイン
- ログアウト
- ユーザ登録
- プロフィール管理
- アカウントリカバリー
- Email検証
- MFA
UIはご自分で、というものなので、最小構成としては以下のようになります。Your Appと書いた部分はサーバサイド・ブラウザ・ネイティブアプリケーションです。Cookieを共有するため、KratosとYour Appはトップレベルドメインは同じである必要があります。
前段にプロキシを挟んであげると、同じドメインできますし、 認証認可等、全く保護されていないAdmin APIを叩きたいときに ORY Oathkeeper のようなIAPを使えば、認可をつけることができます。
ログインやユーザ登録などFormの流れ
Kratosに送信するためのUIを自分で提供する都合上、Formを表示するための実装が結構面倒です。どのFormも大体同じ流れです。
- User AgentがYour Appにアクセス。
- Your AppはORY Kratosにリダイレクト。
- KratosはFlow IDをURLパラメータにつけてYour Appにリダイレクトで戻す。
- Your AppはFlow IDを使ってKratosのAPIを叩く。APIレスポンスを元にFormを組み立てる。メッセージやデフォルト値などもKratosのAPIレスポンス指示に書いてある。
- ユーザがフォームを入力し、Kratosに送信。
- 送信が成功したらリダイレクト。リダイレクト先は設定もしくは、Step 2のときにURLパラメータで指定された値。エラーがあれば、Step 2に戻る。
ここでは簡易的に書きましたが、公式ドキュメントではもっと詳しくシーケンス図で説明されています。
大まかな流れ自体はORY Hydraを使ったことある人であれば、ちょっと似ているので馴染みがあると思いますが、ここで面食らうのは「Kratosの支持通りにFormを組み立てる」ところです。
通常、ログインやユーザー登録などはフォームごとに実装することが多いと思いますが、Kratosの場合は、Kratosの指示(JSON)から自サービスのUIデザインのFormを組み立てるしくみを実装する必要があります。
実装サンプルはこちら。サンプルのpartialsディレクトリの中の実装を自サービスのデザインに合わせて実装するイメージです。ただ、このサンプルの通りに実装すると、ViewにKratosの複雑性を持ち込んでしまうことになるので、フロントエンド・サーバサイドで分業するなら、サーバサイドでKratosのUI指示を変換することを検討したほうがいいかもしれません。
各機能の特徴
ユーザ登録・プロフィール管理
ユーザ登録やプロフィール設定では、ユーザのスキーマを予め定義しておき、その定義に従ってユーザ登録・プロフィール変更のフォームの項目が生成されます。スキーマは1つだけでなく、複数定義することができます。例えばEmailとパスワードだけのスキーマを定義する場合は以下のようになります。
{
"$id": "http://mydomain.com/schemas/v2/customer.schema.json",
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "A customer (v2)",
"type": "object",
"properties": {
"traits": {
"type": "object",
"properties": {
"email": {
"title": "E-Mail",
"type": "string",
"format": "email",
// This tells Ory Kratos that the field should be used as the "username" for the username+password flow.
// It is an extension to the regular JSON Schema vocabulary.
"ory.sh/kratos": {
"credentials": {
"password": {
"identifier": true
}
}
}
}
}
}
}
}
注意が必要なのは、ここで定義したものはすべてユーザ自身が入力できてしまうことです。システム側で管理したいユーザに値を触られたくないプロパティは今のところ、Kratosに持たせることはできないので、それを実現するにはYour App側で管理することになります。
一応、issueは上がっていますが、実装優先順位的にすぐに実装されなさそうなので、早く欲しい場合はコントリビュートが必要です。
https://github.com/ory/kratos/issues/47
ログイン
KratosではPasswordを使ったログインとOpenID Connectを使用したソーシャルサインインに対応しています。OpenID Connectといえば、ORYにはOpenID Providerを実装したORY Hydraがありますが、Hydraとのシームレスな連携は未実装で、連携できるようにYour Appに実装する必要があります。
将来的に実装されるようですが、これも優先度が低く未実装です。とはいえ、この実装はそこまで面倒ではないので、自分で実装してまってもいいかなと思います。
https://github.com/ory/kratos/issues/273
MFA / 2FA
Kratosは TOTP、WebAuthn、Lookup Secretに対応しています。これらはKratosの設定で有効化できます。また、AAL(Authenticator Assurance Level)も対応されており、現状ではAAL1(パスワード or OIDCログイン)もしくはAAL2(パスワード or OIDCログイン + TOTP or WebAuthn or Lookup Secret)を要求できます。ログインのフロー開始時、Kratosにリダイレクトする際にパラメータで aal=aal2
のように指定することができ、その後、セッションを取得した際にもAALを確認することができます。
{
...
"authenticator_assurance_level": "aal2",
...
}
https://www.ory.sh/kratos/docs/reference/api#operation/toSession
アカウントリカバリー
Emailを入力したら、リカバリーメールが飛び、メール内のリンクをクリックするとセッションが発行され、パスワードを設定できるページに飛びます。将来的にはEmail以外も対応しそうですが、今の時点ではEmailのみです。
https://www.ory.sh/kratos/docs/guides/account-recovery-password-reset
その他
組織アカウントとの相性が悪い
Kratosではユーザが編集できない情報を設定できないので、例えば組織IDを紐づけたり、組織の管理者がアカウントを作成して、Emailは変更されたくないなどの要件があったときは、Your Appで組織IDを持つようにしたり、Emailが更新されないように、KratosにForm送信が届く前にバリデーションをするなどの工夫が必要になります。
また、招待も一応できるものの、ユーザ体験としては微妙です。Admin APIを使ってユーザを作成し、アカウントリカバリーフローを使ってパスワードを設定させるというものですが、Admin APIを使ったユーザ作成時には Kratosがメールを送信してくれないので、自分で送信することになります。このメールをユーザがクリックしてもKratosとしてはEmail Verifiedにならないので、Kratosからどこかのタイミング(リカバリーフロー中もしくはパスワード設定後)もう一度、 メールが送信され、このメール中のリンクを踏むとEmail Verifiedになります。
https://www.ory.sh/kratos/docs/admin/managing-users-identities
以上を踏まえるとこんな感じの構成になります。Proxyから Kratosに直接プロキシされていたリクエストはYour Appを通って、必要に応じてバリデーションなどの追加処理を行います。
まとめ
ヘッドレスIDサーバのOSS、ORY Kratosの紹介をしました。
まだalphaバージョンで、足りない部分はたくさんありますが、それでも自分で一から実装するくらいなら、使ってもいいんじゃないかと思います。