Skip to content

CIBA

CIBA is an authentication flow where the client can initiate an authentication request for a user without the user being present at the client device. The authentication happens on a separate device (e.g., mobile phone) via a backchannel.

Overview

Why Use CIBA?

Use Cases

  • IoT Devices: Authenticate users on devices without input capabilities
  • Call Centers: Agent initiates authentication for customer on their mobile device
  • Banking: Transaction approval via mobile app while using web application
  • Smart TVs: User authenticates on their phone instead of typing on TV remote

Comparison with Device Flow

FeatureCIBADevice Flow
User IdentificationClient provides user hintUser enters code
InitiationClient-initiatedUser-initiated
User DiscoveryServer knows the userUser self-identifies
Best ForKnown user, backchannelUnknown user, self-service

How CIBA Works

Flow Overview

  1. Client initiates request: Sends POST /bc-authorize with login_hint
  2. Server sends notification: Notifies user on their device (push, SMS, email)
  3. User approves: User approves the request on their device
  4. Client polls for tokens: Client polls /token endpoint (poll mode)
  5. Server returns tokens: After user approval, returns tokens

Token Delivery Modes

1. Poll Mode (Default)

Client polls the token endpoint with auth_req_id:

POST /token
grant_type=urn:openid:params:grant-type:ciba
&auth_req_id=1c266114-a1be-4252-8ad1-04986c5b9ac1
&client_id=my_client_id
&client_secret=my_client_secret

2. Ping Mode

Server sends HTTP POST notification when user approves, then client fetches tokens:

POST https://client.example.com/ciba/notify
Content-Type: application/json
{
"auth_req_id": "1c266114-a1be-4252-8ad1-04986c5b9ac1"
}

3. Push Mode

Server sends tokens directly in the notification:

POST https://client.example.com/ciba/notify
Content-Type: application/json
{
"auth_req_id": "1c266114-a1be-4252-8ad1-04986c5b9ac1",
"access_token": "eyJhbGc...",
"token_type": "Bearer",
"expires_in": 3600,
"id_token": "eyJhbGc..."
}

API Reference

Backchannel Authentication Endpoint

POST /bc-authorize

Request

POST /bc-authorize HTTP/1.1
Content-Type: application/x-www-form-urlencoded
scope=openid+profile+email
&client_id=my_client_id
&client_secret=my_client_secret
&login_hint=[email protected]
&binding_message=Transaction+ID:+12345

Request Parameters

ParameterRequiredDescription
scopeYesOAuth scopes (must include openid)
client_idYesClient identifier
login_hintOne of*User identifier (email, phone, username)
login_hint_tokenOne of*JWT containing login hint
id_token_hintOne of*Previously issued ID token
binding_messageNoHuman-readable message (max 140 chars)
user_codeNoUser verification code
requested_expiryNoRequest expiry in seconds
client_notification_tokenCond.Required for ping/push modes

*One of login_hint, login_hint_token, or id_token_hint is required

Response

{
"auth_req_id": "1c266114-a1be-4252-8ad1-04986c5b9ac1",
"expires_in": 300,
"interval": 5
}

Token Endpoint (Poll Mode)

POST /token

POST /token HTTP/1.1
Content-Type: application/x-www-form-urlencoded
grant_type=urn:openid:params:grant-type:ciba
&client_id=my_client_id
&client_secret=my_client_secret
&auth_req_id=1c266114-a1be-4252-8ad1-04986c5b9ac1

Response States

Pending:

{
"error": "authorization_pending",
"error_description": "User has not yet authorized the authentication request"
}

Slow Down:

{
"error": "slow_down",
"error_description": "You are polling too frequently. Please slow down."
}

Denied:

{
"error": "access_denied",
"error_description": "User denied the authentication request"
}

Success:

{
"access_token": "eyJhbGc...",
"token_type": "Bearer",
"expires_in": 3600,
"id_token": "eyJhbGc...",
"refresh_token": "eyJhbGc...",
"scope": "openid profile email"
}

Login Hint Formats

The login_hint parameter supports multiple formats:

Email

Phone (E.164)

login_hint=+14155552671
login_hint=tel:+14155552671

Subject Identifier

login_hint=sub:user123

Username

login_hint=johndoe

Binding Message

The binding_message is displayed to the user during approval:

binding_message=Sign in to Banking App
binding_message=Transaction ID: 12345
binding_message=Approve payment of $100.00

Constraints:

  • Maximum 140 characters
  • Unicode letters, numbers, punctuation, and spaces allowed
  • Displayed prominently in user approval UI

Usage Example

// 1. Initiate CIBA request
const cibaResponse = await fetch('https://auth.example.com/bc-authorize', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
scope: 'openid profile email',
client_id: 'my_client_id',
client_secret: 'my_client_secret',
login_hint: '[email protected]',
binding_message: 'Sign in to My App',
}),
});
const { auth_req_id, interval } = await cibaResponse.json();
// 2. Poll for tokens
let tokens;
while (!tokens) {
await new Promise(resolve => setTimeout(resolve, interval * 1000));
const tokenResponse = await fetch('https://auth.example.com/token', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'urn:openid:params:grant-type:ciba',
client_id: 'my_client_id',
client_secret: 'my_client_secret',
auth_req_id,
}),
});
if (tokenResponse.ok) {
tokens = await tokenResponse.json();
}
}
console.log('Authenticated:', tokens);

Security Considerations

Login Hint Validation

  • Validate login hints are properly formatted
  • Verify user exists before initiating notification
  • Rate limit per login hint to prevent spam

Binding Message Injection

  • Sanitize binding messages to prevent phishing
  • Display raw text only, no HTML or scripts
  • Limit length to prevent UI issues

Replay Protection

  • auth_req_id is single-use only
  • Requests expire after configured timeout (default 5 minutes)
  • Token issuance is atomic and tracked

Client Authentication

  • Always require client authentication for CIBA
  • Use client_secret or mutual TLS
  • Validate client is authorized for CIBA grant type

Rate Limiting

  • bc-authorize: 10 requests per minute per client
  • Token endpoint (polling): Respects interval parameter
  • Notification delivery: 5 notifications per minute per user

Client Registration

Register a client with CIBA support:

{
"client_name": "My CIBA App",
"grant_types": ["urn:openid:params:grant-type:ciba"],
"backchannel_token_delivery_mode": "poll",
"backchannel_client_notification_endpoint": "https://app.example.com/ciba/notify",
"backchannel_user_code_parameter": true
}

Discovery Metadata

CIBA support is advertised in the discovery document:

{
"backchannel_authentication_endpoint": "https://auth.example.com/bc-authorize",
"backchannel_token_delivery_modes_supported": ["poll", "ping", "push"],
"backchannel_user_code_parameter_supported": true,
"grant_types_supported": [
"authorization_code",
"refresh_token",
"urn:openid:params:grant-type:ciba"
]
}

Error Codes

ErrorHTTP StatusDescription
invalid_request400Missing required parameter or invalid format
unauthorized_client401Client not registered for CIBA
expired_token400Auth request expired before approval
authorization_pending400User hasn’t approved yet
slow_down400Client polling too frequently
access_denied403User denied the request

References