Skip to Content
GuidesAuthenticationCIBA (Backchannel Auth)

CIBA (Backchannel Authentication)

Client Initiated Backchannel Authentication (CIBA) is an OpenID Connect extension that allows a client application to initiate authentication on behalf of a user without requiring the user to interact with the client directly. Instead, the user receives a notification (via SMS, email, or push) on a separate device and approves or denies the request there.

Common use cases:

  • A call center agent authenticates a customer over the phone by triggering an approval on the customer’s mobile device
  • A payment terminal requests approval from the account holder’s phone before processing a high-value transaction
  • A desktop application delegates login to the user’s phone for a passwordless experience
  • A backend service initiates step-up authentication when a sensitive operation is requested

How It Works

CIBA decouples the device where authentication is initiated from the device where the user provides consent:

  1. The client sends a backchannel authentication request to /api/oauth/ciba with a login_hint (email, phone number, or user ID) identifying the user
  2. Auris validates the request and sends a notification to the user on their registered device or channel
  3. The user sees the request details (application name, binding message) and approves or denies
  4. The client receives the result via one of three modes: polling, ping (callback), or push

Notification Modes

Auris supports three modes for delivering the authentication result to the client:

ModeHow It WorksBest For
PollClient polls the token endpoint at regular intervals until the user respondsSimple integrations, server-side clients
PingAuris sends a notification to a pre-registered callback URL, then the client exchanges the auth request ID for a tokenEvent-driven architectures
PushAuris delivers the token directly to a pre-registered callback URLLow-latency requirements

Poll mode is the simplest to implement and is recommended for most use cases. Ping and push modes require a publicly accessible callback URL and proper webhook security.


Console Setup

Enable CIBA

In the Auris Console, go to Applications and select your application. Under the Settings tab, toggle Enable CIBA to on.

Configure Notification Mode

Select the notification mode (Poll, Ping, or Push). For Ping and Push modes, provide a Callback URL where Auris will send notifications.

Set Notification Channel

Choose how users receive the authentication request notification:

ChannelRequirements
EmailUser must have a verified email address
SMSUser must have a verified phone number. Requires SMS provider configuration (Twilio).
PushRequires a custom push notification integration (advanced)

Configure Request Lifetime

Set the maximum time a CIBA authentication request remains valid before expiring:

SettingDefaultNotes
Request Lifetime300 seconds (5 minutes)Maximum time the user has to approve or deny
Polling Interval5 secondsMinimum interval for poll mode clients

Copy Credentials

CIBA requires a confidential client. Copy the Client ID and Client Secret from the Credentials tab.


Implementation

const AURIS_DOMAIN = 'https://auth.yourdomain.com' const CLIENT_ID = 'your-client-id' const CLIENT_SECRET = 'your-client-secret' // Step 1: Initiate backchannel authentication const cibaResponse = await fetch(`${AURIS_DOMAIN}/api/oauth/ciba`, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Authorization': `Basic ${btoa(`${CLIENT_ID}:${CLIENT_SECRET}`)}`, }, body: new URLSearchParams({ scope: 'openid profile', login_hint: '[email protected]', binding_message: 'Approve login to Dashboard', }), }).then(r => r.json()) console.log('Auth request ID:', cibaResponse.auth_req_id) console.log('User will receive a notification...') // Step 2: Poll for the token const token = await pollForCibaToken(cibaResponse) async function pollForCibaToken(cibaResponse) { const interval = cibaResponse.interval * 1000 const expiresAt = Date.now() + cibaResponse.expires_in * 1000 while (Date.now() < expiresAt) { await new Promise(resolve => setTimeout(resolve, interval)) const response = await fetch(`${AURIS_DOMAIN}/api/auth/token`, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Authorization': `Basic ${btoa(`${CLIENT_ID}:${CLIENT_SECRET}`)}`, }, body: new URLSearchParams({ grant_type: 'urn:openid:params:grant-type:ciba', auth_req_id: cibaResponse.auth_req_id, }), }) if (response.ok) { return await response.json() } const error = await response.json() if (error.error === 'authorization_pending') continue if (error.error === 'slow_down') { await new Promise(r => setTimeout(r, 5000)) continue } if (error.error === 'expired_token') { throw new Error('CIBA request expired. User did not respond in time.') } if (error.error === 'access_denied') { throw new Error('User denied the authentication request.') } throw new Error(`CIBA error: ${error.error}`) } throw new Error('CIBA request timed out.') }

CIBA Request Parameters

The backchannel authentication request accepts the following parameters:

ParameterRequiredDescription
scopeYesOpenID Connect scopes (must include openid)
login_hintYesIdentifies the user. Can be an email address, phone number, or user ID.
binding_messageNoShort message displayed to the user on the approval screen (e.g., “Approve login to Dashboard”). Max 128 characters.
requested_expiryNoRequested lifetime of the authentication request in seconds. Capped by the application configuration.
acr_valuesNoRequested Authentication Context Class Reference values for step-up auth

The Binding Message

The binding_message is a critical security feature. It is displayed to the user on the approval notification and should contain enough context for the user to confirm what they are approving:

  • “Approve login to Dashboard” (login)
  • “Confirm payment of EUR 49.99 to ACME Corp” (payment approval)
  • “Authorize support agent to access your account” (call center)

Always include a meaningful binding message. Without it, users cannot distinguish a legitimate CIBA request from a phishing attempt. The binding message should be specific to the current action — never use a generic “Approve login” message for payment or sensitive operations.


Error Handling

Error CodeHTTP StatusMeaning
authorization_pending400User has not yet responded to the notification
slow_down400Client is polling too fast
expired_token400Auth request has expired (user did not respond)
access_denied400User explicitly denied the request
invalid_request400Missing or invalid parameters
unknown_user_id400The login_hint does not match any known user
unauthorized_client401Client is not authorized for CIBA

Security Considerations

  • Confidential client required: CIBA always requires client authentication (client ID + secret). Public clients cannot use CIBA.
  • Short request lifetime: Default 300 seconds. Shorter lifetimes reduce the window for social engineering attacks.
  • User consent required: The user must explicitly approve the request. Auris never auto-approves.
  • Binding message display: The approval UI always shows the binding message, application name, and requested scopes.
  • Notification channel verification: Auris only sends CIBA notifications to verified email addresses or phone numbers.
  • Audit logging: All CIBA requests (initiated, approved, denied, expired) are logged for audit purposes.

API Endpoints

POST/api/oauth/ciba

Initiate a backchannel authentication request. Requires client authentication (Basic auth or client_id/client_secret in body). Returns auth_req_id, expires_in, and interval.

POST/api/auth/token

Token endpoint. For CIBA, set grant_type=urn:openid:params:grant-type:ciba and auth_req_id. Returns access token on user approval, or a polling error code.

GET/api/oauth/ciba/requestsRequires: view:ciba_requests

List active CIBA authentication requests for the tenant. Admin endpoint for monitoring.


Required Permissions

OperationPermission
Enable CIBA on an applicationmanage:applications
Configure CIBA settingsmanage:ciba_config
List active CIBA requestsview:ciba_requests
Initiate/poll for tokenClient authentication only (no user permission)