Skip to content

CIBA — Client-Initiated Backchannel Authentication

CIBA は device flow とは別の形の問題を解きます。device code は 2 つの面が「画面に表示された短いコード」を介して OP で合流します。CIBA ではリクエストを開始する装置がそもそも ユーザに見えていない — 組み込み側の通知サービスが、ユーザがすでに信頼している 別の認証デバイス に要求を届けます。

代表的な構成:

  • 利用デバイス(consumption device) — POS 端末、コールセンタの操作画面、店内 kiosk、銀行の振込承認パネル等。 であるべきかは知っている(ロイヤリティカード、電話番号、口座番号)が、認証する手段はない。
  • 認証デバイス(authentication device) — ユーザのスマホで、銀行アプリがすでにインストール・サインイン済み。組み込み側の通知サービスが「Acme Coffee で 800 円を承認しますか?」などの要求を表示し、ユーザは 承認 / 拒否 をタップする。

利用デバイスはユーザに credential を一切聞きません — OP に「Alice にスマホで承認してもらってください」と頼むだけです。

このページで触れる仕様
用語の補足
  • auth_req_id/bc-authorize の応答として返る不透明な識別子。利用デバイスはこれを使って /token を poll し、認証デバイスはこれに対して承認する。
  • Hint — 利用デバイスが OP に どのユーザ を聞くかを伝える方法。CIBA Core §7.1 で 3 種類が定義されている:
    • login_hint — 組み込み側が subject にマップする不透明値([email protected]、口座番号など)。
    • id_token_hint — 過去に発行された ID トークン。sub claim でユーザを識別する。
    • login_hint_token — 組み込み側が署名検証してから subject にマップする署名付き JWT(別の上流システムが発行したものなど)。
  • 配信モード — OP が承認を利用デバイスに伝える方法:
    • poll — デバイスが auth_req_id/token を poll します。本ライブラリが実装している配信モードはこれだけです。

フローの動き方(poll mode)

CIBA の poll モード
CIBA の poll モードを示した図。POS 端末が backchannel authentication エンドポイントを呼び、OP が login hint を subject に解決し、組み込み側の通知サービスがスタッフのスマホへ届け、端末はユーザが承認するまでトークンエンドポイントを poll します。利用デバイスPOS 端末OPgo-oidc-provider認証デバイススタッフのスマホ1POST /bc-authorizelogin_hint=alice · scope=openid · binding_message2hint を subject に解決するHintResolver → sub=alice1233組み込み側の通知サービスが届ける「Acme Coffee で 800 円を承認?」4200 · { auth_req_id, expires_in: 600, interval: 5 }parloop · interval 秒ごと5POST /token · grant_type=…:ciba · auth_req_id6400 · { error: authorization_pending }その間、別チャネルでユーザがスマホ上で承認する7approve(auth_req_id, sub=alice123)8POST /token — 次の poll9200 · { access_token, id_token, refresh_token? }
端末とスマホは互いに通信しません。両者が触れるのは OP だけです。binding_message が重要なのはそのためで、端末の前にいる人とスマホを持つ人が突き合わせられる唯一の文字列がこれです。

利用デバイスはユーザの credential を持ちません。ユーザは利用デバイスに何も打ちません。認証デバイス — ユーザが銀行アプリにサインイン済みなのですでに認証されている — だけが consent を行使する場所になります。

CIBA と Device Code — どちらを選ぶか

両方とも 2 デバイスです。違いは 「利用デバイスが聞いていることをユーザが知っているか」 です。

Device CodeCIBA
誰が信頼を起こす?ユーザが認証ページに user_code を打ち込む利用デバイスが OP に要求し、組み込み側の認証デバイスサービスが表示する
ユーザは URL を発見する必要がある?はい — verification_uri が画面に出るいいえ — 配備側が認証デバイスをあらかじめ把握している
利用デバイス側の信頼モデル匿名のデバイスがユーザに「結びつけて」とお願いする事前登録されたデバイスが、OP 経由でユーザに「確認して」とお願いする
代表的な利用面スマート TV、ゲーム機、CLI、IoT 機器のペアリングPOS、コールセンタ、不正検知の確認、アプリ内決済
ユーザが打つ識別子user_codeBDWP-HQPK 等)なし — OP はすでにユーザ識別子を持っている(login_hint
誤誘導のリスク低 — URL がデバイス画面に出ている中 — 別経路の通知文言が利用面と一致しているとユーザが信頼する必要がある。binding_message を使ってスマホ側プロンプトに POS の要求内容を表示すること

ユーザが デバイスの目の前にいて デバイスがコード表示できないなら CIBA。ユーザが デバイスから離れていて デバイスが画面を持っているなら device code。CIBA の認証デバイスは事前にユーザを知っている必要があり、device code の verification ページは任意のサインイン済みブラウザセッションで動きます。

Hint — 「どのユーザか」を OP に伝える

利用デバイスはユーザを認証できないので、OP に どのユーザを承認サービスの対象にするか を伝える必要があります。CIBA Core §7.1 は 3 種類の hint を定義しており、OP は単一の HintResolver interface でそれら全てを受け付けます:

go
op.WithCIBA(
    op.WithCIBAHintResolver(op.HintResolverFunc(
        func(ctx context.Context, kind op.HintKind, value string) (string, error) {
            switch kind {
            case op.HintLoginHint:
                // value = "alice"、"[email protected]"、口座番号など。
                return resolveLoginHint(ctx, value)
            case op.HintIDTokenHint:
                // value は raw JWT ではなく、OP が検証した subject です。
                // OP は署名、issuer、認証済みクライアントの audience を検証しますが、
                // CIBA hint では exp を意図的に検証しません。
                return lookupSubject(ctx, value)
            case op.HintLoginHintToken:
                // value = 信頼している別システムが発行した署名付き JWT。
                return verifyAndMap(ctx, value)
            }
            return "", op.ErrUnknownCIBAUser
        },
    )),
)

op.ErrUnknownCIBAUser を返すと、通信路上の応答は unknown_user_id に丸められます。それ以外のエラーは login_required になります。op.WithCIBA をリゾルバ未指定で呼ぶと op.New は構築に失敗します — リゾルバは必須です。

HintIDTokenHint では、OP が自分の鍵、issuer、認証済みクライアントの audience に対して JWT を検証し、検証済みの sub だけを Resolve に渡します。exp は意図的に検証しません。pairwise subject を登録したクライアントは、sector ごとの sub を元の subject に戻せないため Resolve の前に拒否されます。そのクライアントは login_hint または login_hint_token を使ってください。resolver で raw JWT を parse してはなりません。

binding_message — 誤誘導を防ぐ項目

CIBA の binding_message は利用デバイスが /bc-authorize 時に送れる短い文字列です。OP はこれを認証デバイスに転送し、ユーザのスマホ側プロンプトにレジ係が POS で見ているのと同じ文言を表示できます:

Acme POS 端末 #14: Acme Coffee で 800 円を承認しますか?

[ 承認 ] [ 拒否 ]

binding_message がないと、ユーザは OP の汎用プロンプトしか頼りになりません。「異常なアクティビティを検知しました。この通知を承認してください」のような phishing がはるかに通りやすくなります。仕様上は optional ですが、組み込み側の UX では 必須 として扱ってください。

動かしてみる

examples/32-ciba-pos は完全な POS シナリオを実演します。POS が /bc-authorize に POST、スタッフのスマホ(CIBARequestStore.Approve を直接呼ぶ goroutine でシミュレート)が承認、POS が token 発行まで poll します。end-to-end で 5 秒程度です。

sh
(cd examples/32-ciba-pos && GOWORK=off go run -tags example .)

example はロール別ファイルに分割されています(op.go で OP の組み立て + HintResolverrp.go で POS 側の polling、device.go でスマホ承認のシミュレーション)。

続きはこちら

  • 使い方: CIBA の組み込みop.WithCIBAHintResolver の契約、FAPI-CIBA プロファイル制約、組み込み側の認証デバイスコールバックが CIBARequestStore.Approve に応答する手順。
  • Device Code 入門 — 「ユーザが別の利用面にいる」という同系統の概念。コード表示を使う方式。