[PR #8485] feat: add CIBA plugin for backchannel authentication #8007

Open
opened 2026-03-13 13:56:31 -05:00 by GiteaMirror · 0 comments
Owner

📋 Pull Request Information

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

Base: canary ← Head: feat/ciba-plugin


📝 Commits (1)

  • 8dd8fd8 feat: add @better-auth/ciba plugin for backchannel authentication

📊 Changes

26 files changed (+2930 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 (+266 -0)
➕ packages/ciba/src/bc-authorize.ts (+369 -0)
➕ packages/ciba/src/ciba.test.ts (+656 -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 (+105 -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 @better-auth/ciba, implementing OpenID Connect CIBA Core 1.0.

CIBA enables decoupled authentication: a client (AI agent, CLI tool, IoT device) initiates an auth request via a backchannel endpoint and the user approves on a separate device. No browser redirect needed.

CIBA importance

AI agents increasingly need to act on behalf of users but can't control 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.

New package: @better-auth/ciba

Endpoints:

  • 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

Delivery modes: poll (agent polls token endpoint), ping (server notifies agent, then agent polls), push (server delivers tokens directly)

Features:

  • authorization_details (RFC 9396 RAR) for structured consent (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's switch-default, so plugins can register custom grant types via init() without modifying 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

Documentation

Full plugin docs at docs/content/docs/plugins/ciba.mdx with installation, usage examples, delivery modes, authorization details, endpoint reference, options, schema, error handling, and security considerations.

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 @better-auth/ciba for OpenID Connect CIBA backchannel authentication, enabling agents, CLI tools, and devices to obtain tokens after user approval without browser redirects. Updates oauth-provider to support a custom CIBA grant and publish backchannel metadata.

  • New Features

    • Endpoints: POST /oauth2/bc-authorize, GET /ciba/verify, POST /ciba/authorize, POST /ciba/reject
    • Delivery modes: poll, ping, push (with retries); replay protection and slow_down rate limiting
    • Rich Authorization Requests via authorization_details; id_token_hint validation; binding_message; requested_expiry; resource indicators forwarded
    • HTTPS enforcement for push/ping endpoints (localhost exempt); client re-verification before push delivery
    • Client plugin methods and docs at /docs/plugins/ciba; persistent cibaRequest model for pending requests
  • Refactors

    • oauth-provider exports: createUserTokens, validateClientCredentials, getClient, basicToClientCredentials, checkResource
    • Token endpoint: custom grant type dispatch; grant_type now string; supports CIBA URN and auth_req_id
    • Metadata: adds backchannel_authentication_endpoint, backchannel_token_delivery_modes_supported, backchannel_user_code_parameter_supported
    • OAuth client APIs: grant_types accept strings for extensibility

Written for commit 8dd8fd8e0faada44d79d2788c4b145b578a41deb. 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/8485 **Author:** [@gustavovalverde](https://github.com/gustavovalverde) **Created:** 3/7/2026 **Status:** 🔄 Open **Base:** `canary` ← **Head:** `feat/ciba-plugin` --- ### 📝 Commits (1) - [`8dd8fd8`](https://github.com/better-auth/better-auth/commit/8dd8fd8e0faada44d79d2788c4b145b578a41deb) feat: add @better-auth/ciba plugin for backchannel authentication ### 📊 Changes **26 files changed** (+2930 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` (+266 -0) ➕ `packages/ciba/src/bc-authorize.ts` (+369 -0) ➕ `packages/ciba/src/ciba.test.ts` (+656 -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` (+105 -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 `@better-auth/ciba`, implementing [OpenID Connect CIBA Core 1.0](https://openid.net/specs/openid-client-initiated-backchannel-authentication-core-1_0.html). CIBA enables decoupled authentication: a client (AI agent, CLI tool, IoT device) initiates an auth request via a backchannel endpoint and the user approves on a separate device. No browser redirect needed. ### CIBA importance AI agents increasingly need to act on behalf of users but can't control 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. ### New package: `@better-auth/ciba` **Endpoints:** - `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 **Delivery modes:** poll (agent polls token endpoint), ping (server notifies agent, then agent polls), push (server delivers tokens directly) **Features:** - `authorization_details` (RFC 9396 RAR) for structured consent (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's switch-default, so plugins can register custom grant types via `init()` without modifying 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` ### Documentation Full plugin docs at `docs/content/docs/plugins/ciba.mdx` with installation, usage examples, delivery modes, authorization details, endpoint reference, options, schema, error handling, and security considerations. ### 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 @better-auth/ciba for OpenID Connect CIBA backchannel authentication, enabling agents, CLI tools, and devices to obtain tokens after user approval without browser redirects. Updates oauth-provider to support a custom CIBA grant and publish backchannel metadata. - New Features - Endpoints: POST /oauth2/bc-authorize, GET /ciba/verify, POST /ciba/authorize, POST /ciba/reject - Delivery modes: poll, ping, push (with retries); replay protection and slow_down rate limiting - Rich Authorization Requests via authorization_details; id_token_hint validation; binding_message; requested_expiry; resource indicators forwarded - HTTPS enforcement for push/ping endpoints (localhost exempt); client re-verification before push delivery - Client plugin methods and docs at /docs/plugins/ciba; persistent cibaRequest model for pending requests - Refactors - oauth-provider exports: createUserTokens, validateClientCredentials, getClient, basicToClientCredentials, checkResource - Token endpoint: custom grant type dispatch; grant_type now string; supports CIBA URN and auth_req_id - Metadata: adds backchannel_authentication_endpoint, backchannel_token_delivery_modes_supported, backchannel_user_code_parameter_supported - OAuth client APIs: grant_types accept strings for extensibility <sup>Written for commit 8dd8fd8e0faada44d79d2788c4b145b578a41deb. 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:31 -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#8007