Errors and troubleshooting
This page catalogs the error responses of the Truora Pass integration endpoints and the most common integration mistakes with their fixes.
The two error formats
The Truora Pass API uses two error envelopes, depending on the endpoint and grant:
Truora Pass error envelope — used by the authorization flow and by the authorization_code grant on POST /v1/oauth2/token:
| Field | Type | Description |
|---|---|---|
code |
integer | HTTP status code |
status |
string | HTTP status text |
message |
string | Human-readable description |
error_code |
string (optional) | Machine-readable error identifier |
fields |
array (optional) | Field-level validation details |
RFC 6749 error envelope — used by the refresh_token grant, the CIBA grant on POST /v1/oauth2/token, and POST /v1/oauth2/bc-authorize:
{
"error": "invalid_grant",
"error_description": "refresh token already used"
}
Authorization errors (authorize redirect)
When the Authorization Code flow fails after the request is accepted, Truora Pass redirects the browser back to your redirect_uri with error and error_description query parameters instead of code. With the embedded SDK, the same information arrives through the onError callback as {error, error_description, state}.
Some failures are rejected before any redirect can happen and are shown to the user inside Truora Pass instead — your application only observes that the callback never fires:
| Condition | What happens |
|---|---|
redirect_uri does not exactly match a registered URI |
Request rejected in Truora Pass; no redirect to your application |
| A requested scope is not registered for your application | Request rejected in Truora Pass |
response_type is not code |
Request rejected in Truora Pass |
response_mode is not empty, query, or web_message |
Request rejected in Truora Pass |
response_mode=web_message without web_message enabled, or the embedding origin is not allow-listed |
Request rejected in Truora Pass |
Step-up conditions: acr_not_satisfied, session_too_old, email_domain_not_allowed |
Handled inside the Truora Pass UI; your application sees only the eventual callback success or error |
POST /v1/oauth2/token — authorization_code grant
Send Content-Type: application/json. Errors use the Truora Pass envelope:
| HTTP status | error_code |
Message |
|---|---|---|
| 401 | bad_credentials |
Invalid client credentials |
| 400 | validation_error |
Invalid or expired authorization code, or invalid client/redirect_uri |
POST /v1/oauth2/token — refresh_token grant
Send Content-Type: application/json. Errors use the RFC 6749 envelope:
| HTTP status | error |
When |
|---|---|---|
| 401 | invalid_client |
Client authentication failed |
| 400 | invalid_grant |
The refresh token is invalid or expired |
| 400 | invalid_grant — “refresh token was not issued to this client” |
The token belongs to a different client |
| 400 | invalid_grant — “refresh token already used” |
Reuse detected — the entire token family is revoked |
| 400 | invalid_grant |
The refresh token has expired, or was invalidated by a concurrent refresh (“invalid or already used”) |
| 400 | invalid_scope |
The requested scope is not a subset of the originally granted scopes |
See Refresh tokens for rotation and reuse-detection behavior.
POST /v1/oauth2/token — CIBA grant (polling)
Send Content-Type: application/x-www-form-urlencoded with grant_type=urn:openid:params:grant-type:ciba. Errors use the RFC 6749 envelope; all are HTTP 400 unless noted:
error |
When | What to do |
|---|---|---|
authorization_pending |
The user has not decided yet | Keep polling, waiting interval seconds between attempts |
access_denied |
The user declined the request | Stop — the auth_req_id is consumed |
expired_token |
The auth_req_id is unknown or expired, the request has expired, or it has already been redeemed |
Start a new backchannel request |
invalid_grant |
The auth_req_id was issued to a different client |
Check your client_id |
unsupported_grant_type |
The grant_type value is wrong |
Use urn:openid:params:grant-type:ciba |
unauthorized_client |
Your application is not allowed to use the CIBA grant | Ask your Truora contact to enable it |
invalid_client (HTTP 401) |
Client authentication failed | Check client_id / client_secret |
POST /v1/oauth2/bc-authorize
Errors use the RFC 6749 envelope:
| HTTP status | error |
When |
|---|---|---|
| 400 | invalid_request |
A sensitive scope (documents, background) was requested without binding_message |
| 400 | invalid_request — “the resolved user has no verified phone for delivery” |
The user exists but has no verified phone to receive the approval link |
| 400 | unknown_user_id |
The login_hint does not resolve to a Truora Pass user (it must be an email) |
| 503 | notifier_unavailable |
The approval message could not be delivered — retry later |
See the CIBA flow for the full request reference.
GET /v1/oauth2/userinfo
| HTTP status | Error | When |
|---|---|---|
| 401 | Missing or invalid Bearer token | No Authorization header, or the access token is invalid or expired |
| 401 | insufficient_scope — “Invalid token: missing scopes” |
The token carries no usable scopes |
| 404 | user_not_found |
The user behind the token no longer exists |
Troubleshooting common mistakes
-
redirect_urimismatch. Theredirect_uriin the authorization request must match a registered URI exactly (scheme, host, port, path), and theredirect_urisent to the token endpoint must match the one used in the authorization request. Register every URI you use — see Registering your application. -
Expired or re-used authorization code. Authorization codes live for 10 minutes and are single-use. Exchange the code immediately after receiving it, and never retry a token exchange with the same code — a second attempt returns
validation_error. If the code expired, restart the authorization flow. -
Scope not registered. Every scope in your authorization request must be registered for your application. Remove unregistered scopes, or add them yourself by editing your application in the Truora Pass Dashboard — see Registering your application and the Scopes reference.
-
Wrong
Content-Typeon/token. The token endpoint dispatches byContent-Type: useapplication/jsonfor theauthorization_codeandrefresh_tokengrants, andapplication/x-www-form-urlencodedfor the CIBA grant. Mixing them up makes the request land on the wrong grant handler. -
Polling faster than
interval. In the CIBA flow, wait theinterval(in seconds) returned bybc-authorizebetween polls of the token endpoint — polling faster does not speed up approval. -
Refresh token reuse. Refresh tokens rotate on every use: the old one is consumed and a new one is returned. Presenting an already-used refresh token is treated as reuse, and the entire token family is revoked — your application must send the user through the authorization flow again. Always persist the newest
refresh_tokenfrom each response. See Refresh tokens. -
web_message origin not allow-listed. The embedded SDK requires your application to be registered with
allows_web_messageenabled and the embedding page’s origin included inallowed_web_message_origins. If either is missing, Truora Pass rejects theresponse_mode=web_messagerequest.