Open3

OpenID Connect Client-Initiated Backchannel Authentication Flow - Core 1.0

yapooyapoo

OpenID Connect Client-Initiated Backchannel Authentication Flow - Core 1.0 (CIBA)

概要

CIBA ではユーザー A がサービスを利用するデバイス (Consumption Device; CD) とユーザー B (A と同一でもよい) が認証を行うデバイス (Authentication Device; AD) が分かれており、CD での必要に応じて AD でユーザー B が認証を行う状況を想定する。

このような状況は例えば以下のケースで生じる:

  • 子供が自らのスマートフォンを利用して、親の許諾のもと親のクレジットカードで決済してゲームなどを購入する(このとき子どものスマートフォンが CD で、親のスマートフォンが AD である)
  • 銀行の窓口で行員が業務端末を操作し、顧客の許諾の下で送金などの処理を実行する (窓口の業務端末が CD で、ユーザーの持つスマートフォンなどが AD である)
  • コールセンターのスタッフが電話の相手を認証する (このときコールセンターのスタッフが操作する端末が CD で、電話の相手が認証で用いるデバイスが AD である)。
  • ユーザーがスマートフォンを使って POS 端末における購入処理を承認したい (これは POS 端末が CD、スマートフォンが AD で、CD と AD を操作するユーザーが同じケースである)

CIBA はこのような状況での認証フローを定義する。以下は主な処理の流れである。

図のように CD が ID トークンやアクセストークンを得るための方法が本仕様では Poll Mode, Ping Mode, Push Mode の 3 種類定義されている。これらについては後に述べる。

yapooyapoo

Backchannel Authentication Endpoint

リクエスト

CD が OpenID Provider (OP) の Backchannel Authentication Endpoint に POST リクエストを送ることで CIBA のフローが開始される。このエンドポイントのリクエストパラメータは以下で、これを application/x-www-form-urlencoded で送信する。

parameters 要否 description
scope 必須 通常の OAuth 2.0 や OpenID Connect と同様に、必要なスコープをスペース区切りで指定する。openid は含まれていなくてもよい
client_notification_token Ping Mode または Push Mode の場合に必須 OP が CD へリクエストを行う場合に用いるべき Bearer トークンを指定する。Ping Mode で認証の完了を通知するとき、または Push Mode で ID トークンやアクセストークンを返却する際に用いられる。
acr_values 任意 ユーザーが AD を用いて OP との間で行う認証が満たすべき認証コンテキストクラス。を優先度が高い順にスペース区切りで指定する。このパラメータが指定されるとき、ID トークンには acr クレームが含まれることが推奨される
login_hint_token 任意 AD で認証を行ってほしいユーザーを示すトークン。具体的な仕様は定義されておらず、OP のポリシーとして決める
id_token_hint 任意 AD で認証を行ってほしいユーザーの ID トークンを CD が所持している場合はこのパラメータを指定する
login_hint 任意 AD で認証を行ってほしいユーザーの識別子、メールアドレスなど。
binding_message 任意 CD と AD で表示され、ユーザーが読み取ることを目的としたメッセージ。CD と AD でのトランザクションが関連していることを示すランダム値が含まれているべきとされている。
user_code 任意 後述
requested_expiry 任意 この EP で返却される auth_req_id の有効期間 expires_in を CD が指定したい場合に利用される。秒単位で指定する。

ここで、login_hint_token , id_token_hint , login_hint はいずれか 1 つのみが指定されていなければならない。

またこのエンドポイントではクライアント認証を行わなければならない。認証方法は OpenID Connect Core Section 9 で定義されているものでも良いし、他の方法でも良い。

以下は Section 7.1 に記載されているリクエストの例である

POST /bc-authorize HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded

scope=openid%20email%20example-scope&
client_notification_token=8d67dc78-7faa-4d41-aabd-67707b374255&
binding_message=W4SCT&
login_hint_token=eyJraWQiOiJsdGFjZXNidyIsImFsZyI6IkVTMjU2In0.ey
JzdWJfaWQiOnsiZm9ybWF0IjoicGhvbmUiLCJwaG9uZSI6IisxMzMwMjgxODAwN
CJ9fQ.GSqxJsFbIyojdfMBDv3MOyAplCViVkwQWzthCWuu9_gnKIqECZilwANt1
HfIh3x3JFjaEq-5MZ_B3qeb11NAvg&
client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3A
client-assertion-type%3Ajwt-bearer&
client_assertion=eyJraWQiOiJsdGFjZXNidyIsImFsZyI6IkVTMjU2In0.eyJ
pc3MiOiJzNkJoZFJrcXQzIiwic3ViIjoiczZCaGRSa3F0MyIsImF1ZCI6Imh0dHB
zOi8vc2VydmVyLmV4YW1wbGUuY29tIiwianRpIjoiYmRjLVhzX3NmLTNZTW80RlN
6SUoyUSIsImlhdCI6MTUzNzgxOTQ4NiwiZXhwIjoxNTM3ODE5Nzc3fQ.Ybr8mg_3
E2OptOSsA8rnelYO_y1L-yFaF_j1iemM3ntB61_GN3APe5cl_-5a6cvGlP154XAK
7fL-GaZSdnd9kg

また、リクエストパラメータは OpenID Connect Core Section 6RFC9101 で定義されているように JWT で送信してもよい。以下はその場合のリクエストの例である。

POST /bc-authorize HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded

request=eyJraWQiOiJsdGFjZXNidyIsImFsZyI6IkVTMjU2In0.eyJpc3MiOiJz
NkJoZFJrcXQzIiwiYXVkIjoiaHR0cHM6Ly9zZXJ2ZXIuZXhhbXBsZS5jb20iLCJl
eHAiOjE1Mzc4MjAwODYsImlhdCI6MTUzNzgxOTQ4NiwibmJmIjoxNTM3ODE4ODg2
LCJqdGkiOiI0TFRDcUFDQzJFU0M1QldDbk4zajU4RW5BIiwic2NvcGUiOiJvcGVu
aWQgZW1haWwgZXhhbXBsZS1zY29wZSIsImNsaWVudF9ub3RpZmljYXRpb25fdG9r
ZW4iOiI4ZDY3ZGM3OC03ZmFhLTRkNDEtYWFiZC02NzcwN2IzNzQyNTUiLCJiaW5k
aW5nX21lc3NhZ2UiOiJXNFNDVCIsImxvZ2luX2hpbnRfdG9rZW4iOiJleUpyYVdR
aU9pSnNkR0ZqWlhOaWR5SXNJbUZzWnlJNklrVlRNalUySW4wLmV5SnpkV0pmYVdR
aU9uc2labTl5YldGMElqb2ljR2h2Ym1VaUxDSndhRzl1WlNJNklpc3hNek13TWpn
eE9EQXdOQ0o5ZlEuR1NxeEpzRmJJeW9qZGZNQkR2M01PeUFwbENWaVZrd1FXenRo
Q1d1dTlfZ25LSXFFQ1ppbHdBTnQxSGZJaDN4M0pGamFFcS01TVpfQjNxZWIxMU5B
dmcifQ.ELJvZ2RfBl05bq7nx7pXhagzL9R75mUwO-yZScB1aT3mp480fCQ5KjRVD
womMMjiMKUI4sx8VrPgAZuTfsNSvA&
client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3A
client-assertion-type%3Ajwt-bearer&
client_assertion=eyJraWQiOiJsdGFjZXNidyIsImFsZyI6IkVTMjU2In0.eyJ
pc3MiOiJzNkJoZFJrcXQzIiwic3ViIjoiczZCaGRSa3F0MyIsImF1ZCI6Imh0dHB
zOi8vc2VydmVyLmV4YW1wbGUuY29tIiwianRpIjoiY2NfMVhzc3NmLTJpOG8yZ1B
6SUprMSIsImlhdCI6MTUzNzgxOTQ4NiwiZXhwIjoxNTM3ODE5Nzc3fQ.PWb_VMzU
IbD_aaO5xYpygnAlhRIjzoc6kxg4NixDuD1DVpkKVSBbBweqgbDLV-awkDtuWnyF
yUpHqg83AUV5TA

この request パラメータの JWT のペイロードは以下である

 {
  "iss": "s6BhdRkqt3",
  "aud": "https://server.example.com",
  "exp": 1537820086,
  "iat": 1537819486,
  "nbf": 1537818886,
  "jti": "4LTCqACC2ESC5BWCnN3j58EnA",
  "scope": "openid email example-scope",
  "client_notification_token": "8d67dc78-7faa-4d41-aabd-67707b374255",
  "binding_message": "W4SCT",
  "login_hint_token": "eyJraWQiOiJsdGFjZXNidyIsImFsZyI6IkVTMjU2In0.eyJzdWJfaWQiOnsiZm9ybWF0IjoicGhvbmUiLCJwaG9uZSI6IisxMzMwMjgxODAwNCJ9fQ.GSqxJsFbIyojdfMBDv3MOyAplCViVkwQWzthCWuu9_gnKIqECZilwANt1HfIh3x3JFjaEq-5MZ_B3qeb11NAvg"
 }

User Code

Backchannel Authentication Endpoint の user_code リクエストパラメータは、OP が AD に認証を要求する通知を行ってよいかを判断するのに用いられる値で、login_hint_token , id_token_hint, login_hint で指定されたユーザーのみが知っており、OP で検証可能な文字列のことである (ただし、当該ユーザーが OP にログインする場合のパスワードではない)。

例えば login_hint リクエストパラメータとしてメールアドレスが指定される場合、この値は容易に推測可能であるから、本来認証が要求されるべきではない第三者へ認証リクエストが送られてしまうことを防ぎたいと考えるのは自然なことである。そこで User Code を要求することによって、OP が妥当なリクエストか否かを判断することが可能になる[1]

なお、User Code をユーザーがどのように登録するのかは本仕様では定義されない。

レスポンス

処理成功時には JSON で以下のパラメータが返却される。

parameters 要否 description
auth_req_id 必須 本 EP へのリクエストによって開始されるフローの識別子。利用可能な文字は大文字、小文字のアルファベットとアラビア数字、. , -, _ のみである。[2]
expires_in 必須 auth_req_id の有効期間を秒単位で指定する
interval 任意 Poll Mode で CD がトークンエンドポイントをポーリングする際のリクエスト間隔を秒単位で指定する。指定がない場合は 5 秒とする

以下はレスポンスの例である

HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store

{
  "auth_req_id": "1c266114-a1be-4252-8ad1-04986c5b9ac1",
  "expires_in": 120,
  "interval": 2
}

エラー時には RFC 6749 の Section 4.1.2.1 に従ってエラーを返却する。本仕様で定義される新たなエラーコードが Section 13 で定義されている。

脚注
  1. User Code は CD を操作するユーザーが CD 上で入力しなければならないが、CIBA ではAD と CD は別のユーザーが操作している可能性がある。User Code が用いられる場合これらは同一であることが前提になっているのだろうか? ↩︎

  2. デバイスフローの device_code に似た位置づけのパラメータだと思うのだが、デバイスフローの方ではこのような文字種制限はない ↩︎

yapooyapoo

各種トークンの取得

CIBA では CD が OP から ID トークン、アクセストークン、リフレッシュトークンを得る方法を Poll Mode, Ping Mode, Push Mode の 3 種類示している。

Poll Mode

Poll Mode のとき、CD は Backchannel Authentication Endpoint へのリクエスト後、トークンエンドポイントを Backchannel Authentication Endpoint のレスポンスで得られた interval 以上の間隔でポーリングを行う。OP は AD との間でユーザーの認証が完了したらこのリクエストに対して各種トークンを返却する。

トークンエンドポイントへのリクエストは以下のリクエストパラメータを用いる。

parameter 要否 description
grant_type 必須 固定値 urn:openid:params:grant-type:ciba
auth_req_id 必須 Backchannel Authentication Endpoint で得たもの

以下は Section 10.1 に記載のリクエストの例である

POST /token HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded

grant_type=urn%3Aopenid%3Aparams%3Agrant-type%3Aciba&
auth_req_id=1c266114-a1be-4252-8ad1-04986c5b9ac1&
client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3A
client-assertion-type%3Ajwt-bearer&
client_assertion=eyJraWQiOiJsdGFjZXNidyIsImFsZyI6IkVTMjU2In0.ey
Jpc3MiOiJzNkJoZFJrcXQzIiwic3ViIjoiczZCaGRSa3F0MyIsImF1ZCI6Imh0d
HBzOi8vc2VydmVyLmV4YW1wbGUuY29tL3Rva2VuIiwianRpIjoiLV9wMTZqNkhj
aVhvMzE3aHZaMzEyYyIsImlhdCI6MTUzNzgxOTQ5MSwiZXhwIjoxNTM3ODE5Nzg
yfQ.BjaEoqZb-81gE5zz4UYwNpC3QVSeX5XhH176vg35zjkbq3Zmv_UpHB2ZugR
Va344WchTQVpaSSShLbvha4yziA

成功リクエストは OpenID Connect Core Section 3.1.3.3 に記載のものと同じ (普通のトークンエンドポイントのレスポンス) である。

エラーレスポンスは OpenID Connect Core Section 3.1.3.4 と同じであるが、以下のエラーコードが新規に定義されている[1]

エラーコード description
authorization_pending AD でのユーザーの認証が終わっていない。このとき CD はこのエラーが返却されたリクエストを行ったときから interval 秒経過後に再度リクエストを行うことができる。
slow_down authorization_pending と同様であるが、このとき CD はポーリングの間隔を少なくとも 5 秒以上長くしなければならない
expired_token auth_req_id が失効した。CD は必要であれば再度 Backchannel Authentication Endpoint にリクエストする
access_denied エンドユーザーが認可を拒否した

ここで、OP は AD での認証が終わっていない場合に (Backchannel Authentication Endpoint の interval パラメータとは無関係に) 最大で 30 秒の間トークンエンドポイントへのリクエストに対しレスポンスを返さないでもよい。また、クライアントは最大で 30 秒間 OP からレスポンスが返却されないことに備えた実装をするべきであるとされている。このとき同じ auth_req_id に関するリクエストを並行で行ってはならないが、CD は OP が 30 秒を超えてレスポンスを返さなかった場合は、そのリクエストをキャンセルして新たなリクエストを送ることができる。このようなポーリングのモードを Long Polling としている。

Ping Mode

Ping Mode の場合、OP は AD との間でのユーザーの認証が完了したら、クライアントの Client Notification Endpoint[2] に対して認証の完了を通知する。これをうけて CD はトークンエンドポイントにリクエストして各種トークンを取得する。トークンエンドポイントのリクエストパラメータは Poll Mode と同じである。

OP が Client Notification Endpoint にリクエストする際は、Backchannel Authentication Endpoint へのリクエストで指定された client_notification_token を Bearer Token として送信する。

以下は Section 10.2 に記載されたリクエストの例である。

POST /cb HTTP/1.1
Host: client.example.com
Authorization: Bearer 8d67dc78-7faa-4d41-aabd-67707b374255
Content-Type: application/json

{
 "auth_req_id": "1c266114-a1be-4252-8ad1-04986c5b9ac1"
}

CD はこのリクエストに対し HTTP 204 No Content でレスポンスする。OP は HTTP 200 OK によるレスポンスも受け付けるべきだが、レスポンスボディは無視されるべきである。また CD は HTTP 3xx を返却してはならず、OP はこの場合もリダイレクトに応じてはならない。client_notification_token が不正な場合は HTTP 401 Unauthorized レスポンスを返却する。

Push Mode

Push Mode の場合、OP は AD との間でのユーザーの認証が完了したら Client Notification Endpoint に対して各種トークンを送信する。このとき Ping Mode と同様に client_notification_token が用いられる。また、リクエストボディは通常のトークンエンドポイントのレスポンス (OpenID Connect Core Section 3.1.3.3) に auth_req_id が加わったものである。

また、このとき ID トークンには以下のクレームを含ませなければならず[3]、CD は ID トークンの検証時、通常の検証に加えてこれらのクレームの値の検証もしなければならない。

claim description
urn:openid:params:jwt:claim:auth_req_id auth_req_id
at_hash OpenID Connect Core Section 3.1.3.6 で定義されたもの。ID トークンの JWT のヘッダの alg ヘッダに応じたアルゴリズムによるアクセストークンのハッシュ値
urn:openid:params:jwt:claim:rt_hash リフレッシュトークンを返却する場合、at_hash と同じアルゴリズムによるリフレッシュトークンのハッシュ値を設定する

以下は Section 10.3.1 に記載されたリクエストの例である。

POST /cb HTTP/1.1
Host: client.example.com
Authorization: Bearer 8d67dc78-7faa-4d41-aabd-67707b374255
Content-Type: application/json

{
 "auth_req_id": "1c266114-a1be-4252-8ad1-04986c5b9ac1",
 "access_token": "G5kXH2wHvUra0sHlDy1iTkDJgsgUO1bN",
 "token_type": "Bearer",
 "refresh_token": "4bwc0ESC_IAhflf-ACC_vjD_ltc11ne-8gFPfA2Kx16",
 "expires_in": 120,
 "id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjE2NzcyNiJ9.eyJpc3MiOiJ
   odHRwczovL3NlcnZlci5leGFtcGxlLmNvbSIsInN1YiI6IjI0ODI4OTc2MTAwMS
   IsImF1ZCI6InM2QmhkUmtxdDMiLCJlbWFpbCI6ImphbmVkb2VAZXhhbXBsZS5jb
   20iLCJleHAiOjE1Mzc4MTk4MDMsImlhdCI6MTUzNzgxOTUwMywiYXRfaGFzaCI6
   Ild0MGtWRlhNYWNxdm5IZXlVMDAwMXciLCJ1cm46b3BlbmlkOnBhcmFtczpqd3Q
   6Y2xhaW06cnRfaGFzaCI6InNIYWhDdVNwWENSZzVta0REdnZyNHciLCJ1cm46b3
   BlbmlkOnBhcmFtczpqd3Q6Y2xhaW06YXV0aF9yZXFfaWQiOiIxYzI2NjExNC1hM
   WJlLTQyNTItOGFkMS0wNDk4NmM1YjlhYzEifQ.SGB5_a8E7GjwtoYrkFyqOhLK6
   L8-Wh1nLeREwWj30gNYOZW_ZB2mOeQ5yiXqeKJeNpDPssGUrNo-3N-CqNrbmVCb
   XYTwmNB7IvwE6ZPRcfxFV22oou-NS4-3rEa2ghG44Fi9D9fVURwxrRqgyezeD3H
   HVIFUnCxHUou3OOpj6aOgDqKI4Xl2xJ0-kKAxNR8LljUp64OHgoS-UO3qyfOwIk
   IAR7o4OTK_3Oy78rJNT0Y0RebAWyA81UDCSf_gWVBp-EUTI5CdZ1_odYhwB9OWD
   W1A22Sf6rmjhMHGbQW4A9Z822yiZZveuT_AFZ2hi7yNp8iFPZ8fgPQJ5pPpjA7u
   dg"
}

ここで ID トークンのペイロードは以下である。

{
  "iss": "https://server.example.com",
  "sub": "248289761001",
  "aud": "s6BhdRkqt3",
  "email": "janedoe@example.com",
  "exp": 1537819803,
  "iat": 1537819503,
  "at_hash": "Wt0kVFXMacqvnHeyU0001w",
  "urn:openid:params:jwt:claim:rt_hash": "sHahCuSpXCRg5mkDDvvr4w",
  "urn:openid:params:jwt:claim:auth_req_id":
    "1c266114-a1be-4252-8ad1-04986c5b9ac1"
}

CD はこのリクエストに対し HTTP 204 No Content でレスポンスする。OP は HTTP 200 OK によるレスポンスも受け付けるべきだが、レスポンスボディは無視されるべきである。また CD は HTTP 3xx を返却してはならず、OP はこの場合もリダイレクトに応じてはならない。

また、OP は Client Notification Endpoint で CD にエラーを通知する場合がある。この場合のリクエストパラメータは以下である (トークンを返却するときと同様に Content-Type は application/json である)。

parameter 要否 description
auth_req_id 必須 Backchannel Authentication Endpoint で返却されるもの
error 必須 エラーコード
error_description 任意 エラーの詳細を人間にとって可読性がある文字列で示す

また、エラーコードとしては以下が定義されている。

error description
access_denied ユーザーが認可を拒否した
expired_token auth_req_id が失効した。OP はこのエラーコードを送らなくても良いが、CD はこのエラーの通知をサポートするべきである
transaction_failed 上記以外の何らかの理由でトランザクションが成功しなかった
脚注
  1. OAuth 2.0 Device Authorization Grant (RFC 8628) でも同じようなものが定義されている ↩︎

  2. これは redirect_uri などと同様にあらかじめ OP に登録しておく ↩︎

  3. これらを Poll Mode では含めなくて良いのはなぜだろう? ↩︎