Skip to content

ブラウザを使わないフロー: CIBA と Device Code ​

Device Code(RFC 8628)とCIBA(OpenID Connect Client-Initiated Backchannel Authentication 1.0)は、同じ大きな状況に対して仕様が用意している 2 つの grant です。状況とは「アクセストークンを欲しがるデバイスがまともなブラウザを持てない」こと。スマート TV、ゲーム機、CLI ツール、IoT、音声アシスタント、POS 端末、コールセンタの操作画面、ユーザの代わりに動くサーバ側プロセス、などです。

遠目に見ると 2 つのフローは同じ形に見えます — 「2 つの面が OP で合流して、ユーザはスマホで承認する」。実際には違います。両者は 誰がリクエストを起こすか と ユーザがどう OP に識別されるか で分かれており、その 1 点が他のほぼ全ての違い(通信路上のエンドポイント、ポーリングの主体、フィッシング対策の主軸、適用される規制プロファイル)を決めています。

本ページは選択ガイドです。仕様としての動き方はDevice CodeとCIBAの各ページに置いてあります。

1 段落ずつでまとめる ​

Device Code(RFC 8628). ブラウザを持たないデバイスが OP に「使い切りのコードをくれ」と頼み、自分の画面に表示し、ユーザに「この URL をスマホで開いて、このコードを入力して」と告げます。ユーザは手元のブラウザで認証して承認します。その間デバイスは /token をポーリングし続け、承認が降りるのを待ちます。ユーザの識別は フローの途中で発覚 します — TV の前に誰がやって来るかは OP もデバイスも事前には知りません。

CIBA(Core 1.0). RP はすでにユーザが誰かを知っています — login_hint([email protected]、口座番号など)、id_token_hint(過去に発行された ID トークン)、login_hint_token(上流のシステムが発行した署名付き JWT)のいずれかで。RP は OP に「このユーザを別経路で認証してくれ」と頼みます。組み込み側の通知・認証デバイスサービスがユーザへ通知し、OP はリクエストを保持して RP のポーリングに応答します。本ライブラリは poll 方式だけを実装し、ping / push 配信方式は提供しません。ユーザの識別は RP が事前に与えるもの なので、配備側は承認先の認証デバイスを決められます。

比較 ​

観点Device Code(RFC 8628)CIBA(Core 1.0)
発端ブラウザを持たないデバイス(入力デバイス → OP)RP / API クライアント(RP → OP)
ユーザの識別ユーザが別のブラウザに user_code を入力RP が login_hint / id_token_hint / login_hint_token を事前に渡す
ユーザ側の端末ユーザが手元に持っている任意のブラウザ配備側が事前登録した別経路承認用デバイス
フィッシング対策の主軸デバイスが表示する user_code + ユーザが検証 URI(verification URI)のホストを目視ユーザの認証デバイスに表示する binding_message
ブラウザの関与あり(ユーザのスマホ側)任意 / 不要(組み込み側の認証デバイスが確認する)
ポーリング主体ブラウザを持たないデバイスRP
仕様上のエンドポイント/device_authorization/bc-authorize
token grant_typeurn:ietf:params:oauth:grant-type:device_codeurn:openid:params:grant-type:ciba
主な用途TV アプリ、CLI ツール、kiosk、音声アシスタント、入力手段が乏しい IoT強力な顧客認証(PSD2 風)、金融 / ヘルスケアでの別経路承認、画面共有なしでアクセスをリセットするカスタマーサポートのフロー
本ライブラリでの対応RFC 8628 — op.WithDeviceCodeGrant で有効化OIDC CIBA Core 1.0 — poll モードのみ。Discovery も poll だけを広告し、ping / push は実装しない
ブルートフォース対策op/devicecodekit の opaque な attempt-key リミッタ + レコード単位ロックアウト(MaxUserCodeStrikes、5 回)、さらに slow_down 違反 5 回で poll-abuse ロックアウトpoll-abuse ロックアウト — auth_req_id ごとに slow_down 違反 5 回(CIBAGrant.MaxPollViolations)、閾値超過で audit.CIBAPollAbuseLockout。ユーザが打つコードがないので推測の対象もない
FAPI プロファイルとの関係Device Code は FAPI 2.0 Security Profile で分析済みの認可フローには含まれませんFAPI-CIBA は FAPI 2.0 Security Profile / Message Signing とは別のプロファイルです。本ライブラリの CIBA 設定は JAR、DPoP または mTLS、アクセストークンの有効期間と auth_req_id の有効期間の上限 10 分を要求します

2 つの grant、同じ症状

両方の grant が存在するのは、正攻法の authorization_code + PKCE フローがそもそも「token を欲しがるデバイスにまともなブラウザがある」前提で組まれているからです。その前提は TV、CLI、IoT、音声アシスタント、ユーザの代わりに動くバックエンドサービス、では成り立ちません。RFC 8628 と CIBA は「ブラウザがどこか別の場所にある」という状況の、異なる 2 つの形 を解いています。

どちらを選ぶか — 判定木 ​

順番に 4 つの問いを通ってください。最初の問いでだいたい片付きます。

4 つの問いで CIBA か Device Code かが決まる
CIBA とデバイス認可グラントのどちらを選ぶかを、4 つの問いを順にたどって決める判定木。RP がユーザを既に知っているか、デバイスに画面があるか、ユーザが認証デバイスを事前登録しているか、別経路での承認が規制要件かを順に見ます。RP は事前にユーザを特定できるかフロー開始前に login_hint を渡せるはいCIBAOP がユーザに直接到達できるいいえデバイスに画面があるか短いコードと URL を表示できればよいはいDevice Codeユーザがコードをスマホへ持っていくいいえユーザは認証デバイスを登録済みかOP が到達方法を知っているスマホなどいいえDevice Code通知先が無いのでユーザに来てもらうはい別経路での承認が要件か規制下の金融・ヘルスケアで、端末から離れてはいCIBAbinding_message が 2 つの端末を結ぶいいえ既定は Device Code要求するものが少ない。hint のリゾルバも通知チャネルの運用も要らない
分かれ目は、どちらから話しかけるかです。Device Code はユーザ側に OP を探してもらう方式で、CIBA は事前に伝えられた端末へ OP から働きかける方式です。後者はその通知チャネルを自分で運用している場合にだけ成立します。

1. RP はフロー開始 前 にユーザが誰かを知っているか?

  • はい → CIBA。RP はすでに login_hint(または ID トークン、hint 用トークン)を持っており、/bc-authorize に乗せて送れます。ユーザは自分を識別するための入力をしません。
  • いいえ → Device Code。ユーザは verification ページでサインインすることでフローの中で自分を識別し、OP はそこでユーザが誰かを知ります。

2. token を欲しがるデバイスに画面はあるか?

  • ある → Device Code がそのまま user_code と verification_uri を表示できます。TV / ゲーム機 / CLI の典型ケース。
  • ない(音声アシスタント、ヘッドレス IoT 等) → どちらでも動きます。Device Code は TTS で user_code を読み上げる、verification_uri_complete を QR で出す等の方法が取れます。CIBA は別の認証デバイスを使い、組み込み側の通知サービスが承認 prompt を届けるため、利用デバイス自体の表示は不要です。

3. ユーザは認証デバイスを事前登録しているか?

  • CIBA は前提とします。 事前登録された認証デバイスがないと、組み込み側の承認サービスは届け先を持ちません。そのデバイスを事前登録する工程(銀行アプリ、スタッフのスマホ、規制当局が発行する authenticator、等)は配備の一部です。
  • Device Code は前提としません。 ユーザがサインインできる任意のブラウザセッションで動きます。本人のスマホ、同僚のラップトップ、店舗の kiosk、いずれでも。

4. これは規制下の金融 / ヘルスケアで、別経路承認が要件になっているか?

  • CIBA はこの用途のために設計されています。 旧 FAPI-CIBA-ID1 は FAPI 1.0 と mTLS を基礎としています。本ライブラリの profile.FAPICIBA は JAR を要求し、送信者制約として DPoP または mTLS を認め、アクセストークンの有効期間を 10 分以内に制限します。この設定だけで ID1 への適合は示せません。binding_message は、ユーザが承認するリクエストを識別する助けになります。
  • Device Code は汎用的な仕組みです。 適切に組めば十分機能しますが、規制当局が SCA で名指ししてくる形にはなっていません。

判定木を抜けてもまだ迷うなら、既定としては「画面はあるがブラウザがない」一般消費者向けには Device Code、「RP がユーザを把握済みで、別経路で承認だけしてほしい」業務向けには CIBA を選んでください。

シーケンス図 ​

Device Code(RFC 8628) ​

Device Code: コードは人間が画面の間で運ぶ
デバイス認可グラント。ブラウザを持たないデバイスが device_code と短い user_code を要求し、コードと URL を画面に表示し、ユーザが別のブラウザで承認する間トークンエンドポイントをポーリングします。デバイスブラウザ無し · TV · CLIOPgo-oidc-providerユーザのブラウザスマホやラップトップPOST /device_authorization200 · device_code, user_codeURL とコードを画面に表示user_code=ABCD-EFGHPOST /token · ポーリング400 · authorization_pendingコードを入力して承認POST /token · 次のポーリング200 · access_token, id_token?
デバイスとブラウザは互いに接続されません。両者の間を移動するのは user_code だけで、それを運ぶのは片方の画面を読んでもう片方に入力する人間です。

CIBA(Core 1.0、poll モード) ​

CIBA: OP が登録済みデバイスへ働きかける
CIBA の poll モード。RP が backchannel authentication エンドポイントで login hint を渡し、OP がそれを subject に解決し、組み込み側の通知サービスがユーザの事前登録デバイスへ届け、RP は承認が届くまでポーリングします。RPPOS · コールセンタ画面OPgo-oidc-providerユーザのデバイス事前登録済みPOST /bc-authorizehint を subject に解決ユーザのデバイスへ通知200 · auth_req_idPOST /token · ポーリング400 · authorization_pendingユーザがスマホ上で承認POST /token · 次のポーリング200 · access_token, id_token
Device Code の図との違いは、ここでは OP からユーザに働きかける点です。そのため、解決できる hint と送信できるチャネルの両方が必要になります。その後のポーリングのループはどちらの方式でも同じです。

形は頭の中でマッピングできる程度には似ています。決定的な違いは斜めに伸びる矢印です。Device Code ではユーザが コードを手に OP まで歩いてくる のに対し、CIBA では OP が ユーザがすでに信頼しているデバイスに手を伸ばす。

脅威モデルの並列比較 ​

Phishing — 攻撃者がユーザを騙して 攻撃者の リクエストを承認させる.

  • Device Code: ユーザは入力する URL のホストを目視で確認します。user_code 自体に session 単位の秘密値はありません(エントロピは意図的に控えめ)。ユーザがホストを打ち間違えたり phishing メールのリンクを踏んだりすれば、同じ user_code が攻撃者のサイトでも通ってしまいます。
  • CIBA: binding_message が /bc-authorize に同梱され、ユーザの認証デバイスに表示されます。ユーザは「Acme POS 端末 #14: Acme Coffee で 800 円を承認?」を見てから承認します。文脈のない別経路確認画面(「異常なアクティビティを検知しました、承認しますか?」)が失敗モードです。

user_code への replay / brute-force.

  • Device Code: user_code はユーザが手で入力できるよう短く(BDWP-HQPK 等)作られています。原理的には総当たり可能です。本ライブラリは op/devicecodekit を同梱しており、最初の手入力は生の user_code ではない opaque なサーバ側 ceremony key と VerifyUserCodeByAttemptKey で検証し、その後 ApproveUserCode または DenyUserCode を呼びます。レコード単位のヘルパは MaxUserCodeStrikes(既定 5)も適用します。組み込み側が用意する verification ページは 必ず このヘルパを経由してください。
  • CIBA: ユーザが手で打つコードはありません。auth_req_id は不透明値で OP が発行します。

/token ポーリングへの replay / abuse.

  • 両フローとも、ユーザが判断中は authorization_pending を、interval より速くポーリングしてきたら slow_down を返します。RFC 8628 §3.5 は新しい interval の遵守を必須としており、OP は LastPolledAt と原子的に値を永続化するため、複数レプリカ構成で値をリセットされる経路はありません。
  • 両フローとも、slow_down 違反が 5 回に達するとレコードをロックします。リクエストは reason="poll_abuse" で拒否され、次のポーリングは access_denied になります。CIBA では加えて audit.CIBAPollAbuseLockout が記録され、CIBA の閾値は CIBAGrant.MaxPollViolations で調整できます。

本ライブラリの現状の対応 ​

Device Code(RFC 8628). フル対応で、op.WithDeviceCodeGrant で有効化します(このオプションが grant を有効な集合に加えるので、op.WithGrants に grant.DeviceCode を併記しても何も変わりません)。verification ページ(ユーザが user_code を入力する画面)は 組み込み側がホスト します。最初の手入力は生の user_code ではない opaque なサーバ側 ceremony key と devicecodekit.VerifyUserCodeByAttemptKey で検証し、その後 ApproveUserCode / DenyUserCode を呼びます。devicecodekit.Deps はポインタのまま保持・受け渡しし、既定のリミッタはプロセス内限定です。複数インスタンスでは共有のアトミックな AttemptLimiter を注入します。監査は Deps.AuditLogger 経由です。監査イベントのカタログ:

  • audit.DeviceAuthorizationIssued、audit.DeviceAuthorizationRejected、audit.DeviceAuthorizationUnboundRejected
  • audit.DeviceCodeVerificationApproved、audit.DeviceCodeVerificationDenied、audit.DeviceCodeUserCodeBruteForce
  • audit.DeviceCodeTokenIssued、audit.DeviceCodeTokenRejected、audit.DeviceCodeTokenSlowDown
  • audit.DeviceCodePollObservationFailed(token endpoint がきれいに反映できない状態遷移を観測したとき)
  • audit.DeviceCodeRevoked(公開 Revoke ヘルパから発火)

CIBA(Core 1.0). poll モードのみで、Discovery も poll だけを広告します。ping / push 配信方式は提供しません。op.WithCIBAGrant(op.CIBAGrant{HintResolver: ...}) で有効化します。リゾルバは必須です。HintResolver は組み込み側のフックで、受信した hint(login_hint、id_token_hint、login_hint_token)を subject に解決します。id_token_hint は OP が署名・issuer・認証済みクライアント audience を検証し、検証済み sub だけをリゾルバに渡します。exp は意図的に検証せず、typ が JWT でないトークンは拒否し、pairwise クライアントはリゾルバの前に拒否します。監査イベントのカタログ:

  • audit.CIBAAuthorizationIssued、audit.CIBAAuthorizationRejected、audit.CIBAAuthorizationUnboundRejected
  • audit.CIBAPollAbuseLockout
  • audit.CIBATokenIssued、audit.CIBATokenRejected、audit.CIBATokenSlowDown
  • audit.CIBAPollObservationFailed(token endpoint がきれいに反映できない状態遷移を観測したとき)

認証デバイスの callback は組み込み側が CIBA サブストアを直接呼ぶ経路です。その呼び出しに対して本ライブラリは audit.CIBAAuthDeviceApproved / audit.CIBAAuthDeviceDenied を発火しません。これらの名前は配備側のテレメトリ用のカタログです。

続きはこちら ​