[PR #8484] [CLOSED] feat: add @better-auth/ciba plugin (CIBA backchannel authentication) #8006

Closed
opened 2026-03-13 13:56:29 -05:00 by GiteaMirror · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/better-auth/better-auth/pull/8484
Author: @gustavovalverde
Created: 3/7/2026
Status: Closed

Base: canaryHead: feat/ciba-plugin


📝 Commits (6)

  • a417e3a feat: add @better-auth/ciba plugin for backchannel authentication
  • c89fd36 fix(ciba): lint fixes, remove transitive comments, fix type cast
  • 3fd9516 fix(ciba): validate authorization_details before DB write, fail-closed client check in verify
  • 22fe2a8 fix(ciba,oauth-provider): address review feedback
  • c90eab5 fix(ciba): cast middleware context type for baseURL access
  • 79697c9 fix(ciba): add CIBA to cspell dictionary

📊 Changes

26 files changed (+2905 additions, -75 deletions)

View changed files

📝 .cspell/auth-terms.txt (+1 -0)
docs/content/docs/plugins/ciba.mdx (+667 -0)
📝 docs/content/docs/plugins/index.mdx (+1 -0)
packages/ciba/package.json (+82 -0)
packages/ciba/src/approval.ts (+244 -0)
packages/ciba/src/bc-authorize.ts (+369 -0)
packages/ciba/src/ciba.test.ts (+658 -0)
packages/ciba/src/client.ts (+14 -0)
packages/ciba/src/error-codes.ts (+15 -0)
packages/ciba/src/grant-handler.ts (+163 -0)
packages/ciba/src/index.ts (+109 -0)
packages/ciba/src/push.ts (+100 -0)
packages/ciba/src/schema.ts (+78 -0)
packages/ciba/src/types.ts (+70 -0)
packages/ciba/src/utils.ts (+83 -0)
packages/ciba/src/verify.ts (+90 -0)
packages/ciba/tsconfig.json (+18 -0)
packages/ciba/tsdown.config.ts (+18 -0)
packages/ciba/vitest.config.ts (+9 -0)
📝 packages/oauth-provider/src/index.ts (+6 -0)

...and 6 more files

📄 Description

Summary

Adds a new @better-auth/ciba plugin implementing OpenID Connect Client Initiated Backchannel Authentication (CIBA) Core 1.0.

CIBA enables decoupled authentication flows where a client (AI agent, CLI tool, IoT device, or headless service) initiates an auth request and the user approves on a separate device or channel; no browser redirect needed.

The importance of CIBA

As AI agents increasingly need to act on behalf of users, they need a standardized way to request authorization without controlling a browser. CIBA solves this: the agent calls a backchannel endpoint, the user gets notified (email, push, SMS), approves or denies, and the agent receives tokens. This is the OpenID Foundation's answer to agentic authorization.

What's included

New package: @better-auth/ciba

  • POST /oauth2/bc-authorize — Agent initiates a backchannel auth request with client credentials + user hint
  • GET /ciba/verify — Approval UI fetches request details (client name, scopes, binding message)
  • POST /ciba/authorize / POST /ciba/reject — Authenticated user approves or denies
  • Three delivery modes: poll (agent polls token endpoint), ping (server notifies agent to poll), push (server delivers tokens directly)
  • authorization_details (RFC 9396 RAR) for structured consent — agents can describe exactly what action they want to perform (e.g. purchase details, transfer amounts)
  • id_token_hint validation with JWKS asymmetric verification + HS256 fallback, audience binding
  • binding_message for human-readable context in the approval UI
  • requested_expiry for client-controlled request lifetimes
  • Resource indicators forwarded through the token pipeline
  • HTTPS enforcement on push/ping notification endpoints per CIBA §10.3 (loopback exempt for dev)
  • Rate limiting with slow_down and progressive interval increase
  • Replay protection — requests consumed on token issuance
  • Client re-verification before push token delivery
  • Client plugin with typed methods (ciba.verify(), ciba.authorize(), ciba.reject())

Changes to @better-auth/oauth-provider

  • Export createUserTokens, validateClientCredentials, getClient, basicToClientCredentials, checkResource for plugin reuse
  • Add customGrantTypeHandlers dispatch in the token endpoint switch-default — plugins can register custom grant types via init() without modifying the provider's core code
  • Widen grant_type Zod validation from enum to string for extensibility (dispatch still validates known types)
  • Add CIBA URN to grant_types arrays and backchannel metadata types to AuthorizationServerMetadata
  • Discovery metadata types for backchannel_authentication_endpoint, backchannel_token_delivery_modes_supported, etc.

Documentation

  • Full plugin docs at docs/content/docs/plugins/ciba.mdx with installation steps, usage examples (agent, user approval, polling), delivery modes, authorization details, endpoint reference (<APIMethod>), options, schema (<DatabaseTable>), error handling, security considerations
  • Added to plugin index

Usage

// Server
import { ciba } from "@better-auth/ciba";

export const auth = betterAuth({
  plugins: [
    jwt(),
    oauthProvider({ loginPage: "/sign-in", consentPage: "/consent" }),
    ciba({
      sendNotification: async (data) => {
        await sendEmail({
          to: lookupEmail(data.userId),
          subject: `Approve: ${data.bindingMessage}`,
          body: `Click to approve: ${data.approvalUrl}`,
        });
      },
    }),
  ],
});
// Agent
const { auth_req_id, interval } = await fetch("/api/auth/oauth2/bc-authorize", {
  method: "POST",
  headers: { Authorization: `Basic ${btoa(`${id}:${secret}`)}` },
  body: JSON.stringify({ scope: "openid", login_hint: "user@example.com" }),
}).then(r => r.json());

// Poll until approved

Summary by cubic

Adds a new @better-auth/ciba plugin implementing OpenID Connect CIBA for decoupled backchannel authentication. Adds poll/ping/push delivery, integrates with the OAuth token endpoint via a custom grant, and ships strict validation, security controls, and docs.

  • New Features

    • New package + endpoints: POST /oauth2/bc-authorize, GET /ciba/verify, POST /ciba/authorize, POST /ciba/reject.
    • Delivery modes: poll, ping, push; HTTPS enforced for ping/push with loopback exemption; push retries with backoff and falls back to polling; client_notification_token required for ping/push.
    • Consent and request fields: authorization_details (RAR) with JSON validation, binding_message, requested_expiry, resource indicators.
    • id_token_hint verification via JWKS (asymmetric) with HS256 fallback using the JWT plugin’s issuer; issuer/audience checks.
    • Protections: rate limiting with slow_down, request expiry, replay prevention, client re-verification on push.
    • Discovery metadata extended for backchannel endpoints and delivery modes; CIBA grant wired into the token endpoint via customGrantTypeHandlers; client plugin with typed methods.
  • Refactors & Fixes

    • OAuth provider exports helpers for plugins; grant_type/grant_types accept trimmed strings; adds CIBA URN and backchannel metadata fields.
    • CIBA grant redemption validates client credentials and enforces stored scopes; authorization_details JSON is validated before persistence.
    • /ciba/verify fails closed if the client is missing or disabled; HS256 fallback issuer resolution aligned with the JWT plugin.

Written for commit c90eab58e9. Summary will update on new commits.


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/better-auth/better-auth/pull/8484 **Author:** [@gustavovalverde](https://github.com/gustavovalverde) **Created:** 3/7/2026 **Status:** ❌ Closed **Base:** `canary` ← **Head:** `feat/ciba-plugin` --- ### 📝 Commits (6) - [`a417e3a`](https://github.com/better-auth/better-auth/commit/a417e3af57da4babefe117062216335a2fce3ee2) feat: add @better-auth/ciba plugin for backchannel authentication - [`c89fd36`](https://github.com/better-auth/better-auth/commit/c89fd36a086abecc6e0d3774626c8e643237cad8) fix(ciba): lint fixes, remove transitive comments, fix type cast - [`3fd9516`](https://github.com/better-auth/better-auth/commit/3fd95160031d4741dab13a315a02a75381031a14) fix(ciba): validate authorization_details before DB write, fail-closed client check in verify - [`22fe2a8`](https://github.com/better-auth/better-auth/commit/22fe2a86c6a465516b6e3732b85e6a430ae10326) fix(ciba,oauth-provider): address review feedback - [`c90eab5`](https://github.com/better-auth/better-auth/commit/c90eab58e98653fc8032639d6732b4a67c7f2a01) fix(ciba): cast middleware context type for baseURL access - [`79697c9`](https://github.com/better-auth/better-auth/commit/79697c9ec79e90dc72784d539130a2676298705d) fix(ciba): add CIBA to cspell dictionary ### 📊 Changes **26 files changed** (+2905 additions, -75 deletions) <details> <summary>View changed files</summary> 📝 `.cspell/auth-terms.txt` (+1 -0) ➕ `docs/content/docs/plugins/ciba.mdx` (+667 -0) 📝 `docs/content/docs/plugins/index.mdx` (+1 -0) ➕ `packages/ciba/package.json` (+82 -0) ➕ `packages/ciba/src/approval.ts` (+244 -0) ➕ `packages/ciba/src/bc-authorize.ts` (+369 -0) ➕ `packages/ciba/src/ciba.test.ts` (+658 -0) ➕ `packages/ciba/src/client.ts` (+14 -0) ➕ `packages/ciba/src/error-codes.ts` (+15 -0) ➕ `packages/ciba/src/grant-handler.ts` (+163 -0) ➕ `packages/ciba/src/index.ts` (+109 -0) ➕ `packages/ciba/src/push.ts` (+100 -0) ➕ `packages/ciba/src/schema.ts` (+78 -0) ➕ `packages/ciba/src/types.ts` (+70 -0) ➕ `packages/ciba/src/utils.ts` (+83 -0) ➕ `packages/ciba/src/verify.ts` (+90 -0) ➕ `packages/ciba/tsconfig.json` (+18 -0) ➕ `packages/ciba/tsdown.config.ts` (+18 -0) ➕ `packages/ciba/vitest.config.ts` (+9 -0) 📝 `packages/oauth-provider/src/index.ts` (+6 -0) _...and 6 more files_ </details> ### 📄 Description ## Summary Adds a new `@better-auth/ciba` plugin implementing [OpenID Connect Client Initiated Backchannel Authentication (CIBA) Core 1.0](https://openid.net/specs/openid-client-initiated-backchannel-authentication-core-1_0.html). CIBA enables **decoupled authentication flows** where a client (AI agent, CLI tool, IoT device, or headless service) initiates an auth request and the user approves on a separate device or channel; no browser redirect needed. ### The importance of CIBA As AI agents increasingly need to act on behalf of users, they need a standardized way to request authorization without controlling a browser. CIBA solves this: the agent calls a backchannel endpoint, the user gets notified (email, push, SMS), approves or denies, and the agent receives tokens. This is the OpenID Foundation's answer to agentic authorization. ### What's included **New package: `@better-auth/ciba`** - `POST /oauth2/bc-authorize` — Agent initiates a backchannel auth request with client credentials + user hint - `GET /ciba/verify` — Approval UI fetches request details (client name, scopes, binding message) - `POST /ciba/authorize` / `POST /ciba/reject` — Authenticated user approves or denies - **Three delivery modes**: poll (agent polls token endpoint), ping (server notifies agent to poll), push (server delivers tokens directly) - **`authorization_details`** (RFC 9396 RAR) for structured consent — agents can describe exactly what action they want to perform (e.g. purchase details, transfer amounts) - **`id_token_hint`** validation with JWKS asymmetric verification + HS256 fallback, audience binding - **`binding_message`** for human-readable context in the approval UI - **`requested_expiry`** for client-controlled request lifetimes - **Resource indicators** forwarded through the token pipeline - **HTTPS enforcement** on push/ping notification endpoints per CIBA §10.3 (loopback exempt for dev) - Rate limiting with `slow_down` and progressive interval increase - Replay protection — requests consumed on token issuance - Client re-verification before push token delivery - Client plugin with typed methods (`ciba.verify()`, `ciba.authorize()`, `ciba.reject()`) **Changes to `@better-auth/oauth-provider`** - Export `createUserTokens`, `validateClientCredentials`, `getClient`, `basicToClientCredentials`, `checkResource` for plugin reuse - Add `customGrantTypeHandlers` dispatch in the token endpoint switch-default — plugins can register custom grant types via `init()` without modifying the provider's core code - Widen `grant_type` Zod validation from enum to string for extensibility (dispatch still validates known types) - Add CIBA URN to `grant_types` arrays and backchannel metadata types to `AuthorizationServerMetadata` - Discovery metadata types for `backchannel_authentication_endpoint`, `backchannel_token_delivery_modes_supported`, etc. **Documentation** - Full plugin docs at `docs/content/docs/plugins/ciba.mdx` with installation steps, usage examples (agent, user approval, polling), delivery modes, authorization details, endpoint reference (`<APIMethod>`), options, schema (`<DatabaseTable>`), error handling, security considerations - Added to plugin index ### Usage ```ts // Server import { ciba } from "@better-auth/ciba"; export const auth = betterAuth({ plugins: [ jwt(), oauthProvider({ loginPage: "/sign-in", consentPage: "/consent" }), ciba({ sendNotification: async (data) => { await sendEmail({ to: lookupEmail(data.userId), subject: `Approve: ${data.bindingMessage}`, body: `Click to approve: ${data.approvalUrl}`, }); }, }), ], }); ``` ```ts // Agent const { auth_req_id, interval } = await fetch("/api/auth/oauth2/bc-authorize", { method: "POST", headers: { Authorization: `Basic ${btoa(`${id}:${secret}`)}` }, body: JSON.stringify({ scope: "openid", login_hint: "user@example.com" }), }).then(r => r.json()); // Poll until approved ``` <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Adds a new @better-auth/ciba plugin implementing OpenID Connect CIBA for decoupled backchannel authentication. Adds poll/ping/push delivery, integrates with the OAuth token endpoint via a custom grant, and ships strict validation, security controls, and docs. - New Features - New package + endpoints: POST /oauth2/bc-authorize, GET /ciba/verify, POST /ciba/authorize, POST /ciba/reject. - Delivery modes: poll, ping, push; HTTPS enforced for ping/push with loopback exemption; push retries with backoff and falls back to polling; client_notification_token required for ping/push. - Consent and request fields: authorization_details (RAR) with JSON validation, binding_message, requested_expiry, resource indicators. - id_token_hint verification via JWKS (asymmetric) with HS256 fallback using the JWT plugin’s issuer; issuer/audience checks. - Protections: rate limiting with slow_down, request expiry, replay prevention, client re-verification on push. - Discovery metadata extended for backchannel endpoints and delivery modes; CIBA grant wired into the token endpoint via customGrantTypeHandlers; client plugin with typed methods. - Refactors & Fixes - OAuth provider exports helpers for plugins; grant_type/grant_types accept trimmed strings; adds CIBA URN and backchannel metadata fields. - CIBA grant redemption validates client credentials and enforces stored scopes; authorization_details JSON is validated before persistence. - /ciba/verify fails closed if the client is missing or disabled; HS256 fallback issuer resolution aligned with the JWT plugin. <sup>Written for commit c90eab58e98653fc8032639d6732b4a67c7f2a01. Summary will update on new commits.</sup> <!-- End of auto-generated description by cubic. --> --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
GiteaMirror added the pull-request label 2026-03-13 13:56:29 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#8006