CIBA Endpoints

Client Initiated Backchannel Authentication — for human-in-the-loop authorization flows where an agent requests approval from a user out-of-band.


Initiate Authorization Request

POST /api/v1/ciba/authorize

Agent requests authorization from a user for a sensitive action.

Headers

  • Authorization: Bearer <agentToken>
  • X-Bulwark-Tenant: <tenant-id>

Body

{
  "userId": "usr_01j...",
  "scope": "approve:payment",
  "bindingMessage": "Approve payment of $500 to Acme Corp?",
  "requestedExpiry": 300,
  "notificationHint": "push",
  "context": {
    "amount": 500,
    "recipient": "Acme Corp",
    "currency": "USD"
  }
}

Response 200

{
  "data": {
    "authReqId": "auth_req_01j...",
    "expiresIn": 300,
    "interval": 5
  }
}

The agent polls using authReqId while the user is notified out-of-band.


Poll Authorization Status

GET /api/v1/ciba/token/{authReqId}

Poll to check if the user has approved or denied.

Response — Pending 202

{
  "data": {
    "status": "pending"
  }
}

Response — Approved 200

{
  "data": {
    "status": "approved",
    "accessToken": "eyJ...",
    "scope": "approve:payment",
    "approvedAt": "2026-03-18T13:05:00Z"
  }
}

Response — Denied 200

{
  "data": {
    "status": "denied",
    "deniedAt": "2026-03-18T13:04:00Z"
  }
}

Response — Expired 410

{
  "error": {
    "code": "AUTH_REQUEST_EXPIRED",
    "message": "Authorization request expired without a decision."
  }
}

Approve (User-facing)

POST /api/v1/ciba/approve/{authReqId}

Called by the user (via dashboard or mobile push) to approve.

Headers

  • Authorization: Bearer <userToken>

Response 200

{
  "data": {
    "authReqId": "auth_req_01j...",
    "status": "approved"
  }
}

Deny (User-facing)

POST /api/v1/ciba/deny/{authReqId}

Headers

  • Authorization: Bearer <userToken>

Response 200

{
  "data": {
    "authReqId": "auth_req_01j...",
    "status": "denied"
  }
}