SenseCrypt Docs
Reference

Error codes

The complete SenseCrypt error taxonomy — OAuth/OIDC, SAML, SCIM, and device-plane error codes, their HTTP statuses, the exact envelopes, and what each one means.

This page catalogs the errors SenseCrypt returns across its four protocol surfaces. Many authentication failures are deliberately opaque to prevent enumeration: treat auth failures as opaque, and branch only on the documented codes below — never on the exact wording of a message.

Error envelopes

SenseCrypt uses three distinct error shapes depending on the surface:

OAuth/OIDC protocol envelope — RFC 6749 §5.2, used by the OIDC and SAML protocol endpoints:

{ "error": "invalid_grant", "error_description": "code invalid, expired, or already used" }

error_description is included only when it adds detail beyond the code.

Management / device envelope — used by the device plane, UserInfo, and management routes. Clients branch on error (and kind where present) and must treat unknown values as generic failures:

{ "error": "unauthorized", "message": "unauthorized", "kind": "replayed_request" }

SCIM envelope — the SCIM-mandated shape:

{ "schemas": ["urn:ietf:params:scim:api:messages:2.0:Error"], "status": "409", "scimType": "uniqueness", "detail": "a user with this userName or email already exists" }

A note on statuses: among OAuth errors, invalid_client is 401; every other OAuth error (invalid_grant, invalid_request, invalid_target, invalid_scope, unsupported_grant_type, unsupported_response_type, and the CIBA codes) is 400.


OAuth / OIDC errors

Token endpoint (POST /v1/idp/oidc/token)

CodeHTTPMeaning
unsupported_grant_type400grant_type isn't one of authorization_code, refresh_token, client_credentials, or CIBA.
invalid_grant400The authorization code is invalid, expired, or already used. This is deliberately opaque — a cross-tenant client and a failed access-gate check also collapse to this same message (see below).
invalid_grant400PKCE failure — a code_verifier is required but missing, fails the RFC 7636 format check, doesn't match the challenge, or was supplied when the session stored no challenge.
invalid_scope400A requested scope isn't granted to the client (re-checked here and on refresh).
login_required400max_age was exceeded and reauthentication is required.

client_credentials (M2M):

CodeHTTPMeaning
invalid_client401Missing client_id, unknown app, wrong secret, foreign tenant, or disabled app — all one opaque failure (unknown client_id or bad client_secret).
invalid_target400The requested audience/resource isn't the tenant's Management API identifier.

refresh_token:

CodeHTTPMeaning
invalid_grant400The refresh token is missing, unknown, revoked, expired, or a reuse was detected (which revokes the entire token family).
invalid_scope400The scope re-check on refresh failed.

Authorize endpoint (GET /v1/idp/oidc/authorize)

CodeHTTPMeaning
unauthorized401Unknown client, cross-tenant client, or a redirect_uri not on the allow-list — deliberately identical to prevent client enumeration. (This uses the management-envelope unauthorized, not an OAuth code.)
unsupported_response_type400response_type isn't code.
invalid_request400Missing response_type or redirect_uri (direct flow).
invalid_target400The client isn't authorized to request the resource audience.
invalid_request_uri400The PAR request_uri is malformed, empty, or already consumed/expired (the last is opaque).
invalid_scope400A requested scope isn't bound to the client.
invalid_request400PKCE required but no code_challenge, or an unsupported code_challenge_method (only S256 is accepted; plain is rejected).

PAR endpoint (POST /v1/idp/oidc/par)

Success is 201. Errors:

CodeHTTPMeaning
unsupported_response_type400Only response_type=code is supported.
invalid_request400Unknown client for this issuer, or a redirect_uri not on the allow-list.
invalid_target400The client isn't authorized to request the resource audience.
invalid_scope400A requested scope isn't bound to the client.
invalid_request400PKCE gate (as on /authorize).
invalid_client401Client authentication failed (see Client authentication).

Introspection (POST /v1/idp/oidc/introspect)

Per RFC 7662, an unverifiable, expired, revoked, wrong-audience, or unknown token returns {"active": false} with HTTP 200 — never an error. True errors:

CodeHTTPMeaning
invalid_client401Client authentication failed.
invalid_client401Introspection requires a confidential client — a public/SPA client is rejected.
invalid_request400The token parameter is missing.

Revocation (POST /v1/idp/oidc/revoke)

Per RFC 7009, an invalid/unknown/already-revoked token returns an empty 200 (no validity oracle). But client authentication still gates the call:

CodeHTTPMeaning
invalid_client401Client authentication failed (cross-tenant client).
invalid_request400The token parameter is missing.

UserInfo (GET /v1/idp/oidc/userinfo)

All failures are 401 and use the management envelope ({"error": "unauthorized", ...}, with a reason field) — note this differs from the RFC 6749 shape used elsewhere, and no WWW-Authenticate header is sent. Triggers include: no bearer token, a bad/invalid access token, a token whose token_use isn't access, a revoked token, or a sub that resolves to no active user.

RP-Initiated Logout (GET /v1/idp/oidc/logout)

All failures are 400 with error: "invalid_request". An id_token_hint is required (there's no server-side SSO cookie). Other triggers: an invalid hint, a client_id that doesn't match the hint's aud, an unresolvable client, or a post_logout_redirect_uri not on the client's dedicated allow-list.

CIBA backchannel start (POST /v1/idp/oidc/bc-authorize)

CodeHTTPMeaning
invalid_client401Unknown client for this issuer.
unauthorized_client400The client isn't registered for CIBA.
invalid_request400scope must include openid; exactly one hint is required; binding_message must not exceed 512 characters; or a client_notification_token is required for ping/push delivery.
invalid_target400The client isn't authorized to request the resource audience.
unknown_user_id400The hint didn't resolve to an eligible user. Deliberately the same whether the user is unknown or merely ungated.
invalid_scope400A requested scope isn't bound to the client.

There is no invalid_binding_message code — an over-length binding message is invalid_request.

CIBA token polling (at POST /v1/idp/oidc/token)

These are returned in the RFC 6749 shape at HTTP 400. The first two are normal poll responses, not terminal failures:

CodeHTTPMeaning
authorization_pending400The user hasn't approved yet. Keep polling at the advertised interval.
slow_down400You're polling faster than the advertised interval. Back off.
expired_token400The auth_req_id has expired.
access_denied400The user denied the request.
unauthorized_client400A push-delivery client must not poll the token endpoint.
invalid_grant400Unknown or already-used auth_req_id.

Client authentication errors

Across /token, /par, /introspect, /revoke, and /bc-authorize, all client-authentication failures collapse to invalid_client (401) so the endpoint can't leak which side failed. This covers: unknown client_id, wrong secret, a malformed Authorization header, multiple auth mechanisms, an auth method the client isn't registered for, a public/SPA client presenting a credential, and any client_assertion verification failure (client_secret_jwt / private_key_jwt).


SAML errors

SAML protocol endpoints use the OAuth/OIDC envelope shape. Common codes:

CodeHTTPMeaning
unauthorized401Unknown SP entityID, IdP-initiated SSO not allowed for the SP, or a failed delivery gate — opaque, to prevent entityID enumeration.
invalid_request400Invalid SAMLRequest (parse failure), request-signature verification failure, an unregistered AssertionConsumerServiceURL, an unsatisfiable NameID policy (carrying the SAML status URN urn:oasis:names:tc:SAML:2.0:status:InvalidNameIDPolicy), or neither SAMLRequest nor sp present.
invalid_grant400The post-back session has no authorized subject.
not_found404The SAML session isn't ready or already delivered, or ?kid= names no published certificate.

Single Logout (SLO) is not implemented — there is no SLO endpoint or LogoutRequest handling, and no IdP-side SSO session to propagate a logout from. Request-signature verification and assertion encryption require RSA SP keys.


SCIM errors

SCIM uses the envelope shown above. The scimType field is present on 400-class errors; auth failures (401/403) carry only a detail message.

scimTypeHTTPWhen
invalidFilter400An unknown attribute path, unsupported operator, or malformed/over-long filter expression. Never a silent full-directory listing.
invalidValue400A missing required field on create (userName + a primary email), an illegal remove (of active, userName, or emails), leaving a user with no primary email, attributes and excludedAttributes supplied together, a bad date in a filter, or a malformed bulk request.
invalidSyntax400An unsupported PATCH op (not add/replace/remove).
invalidPath400An unsupported PATCH value-path, or a bulk path/id problem.
noTarget400A PATCH value-path remove/replace matched no value.
uniqueness409A userName/email collision (users) or a displayName collision (groups).
tooMany413More than 1000 operations in a bulk request.
tooLarge413A bulk payload over 1 MiB. (Note: tooLarge is a SenseCrypt extension, not a standard RFC 7644 scimType.)

Errors without a scimType:

HTTPWhen
401Missing or invalid bearer token — detail names the reason (e.g. admin access token required).
403The token lacks the scim:read / scim:write capability for the method — detail is missing capability: scim:read (or scim:write).
404User/Group/Schema not found. (A console-managed group is a deliberate 404 to a SCIM caller — no leak.)
412A conditional write whose If-Match ETag doesn't match the current version (resource has changed).

A remove on members without a target is rejected as 400 invalidValue — it is never treated as a clear-all.

Supported filter operators: eq ne co sw ew gt ge lt le pr, plus and/or/not, parenthesized grouping, and emails[...] value paths. Multi-valued complex attributes support presence (pr) only.


Device-plane errors

Every phone-originated request is a signed request. Device errors use the management envelope; the mobile SDK branches on error and, for unauthorized, on the kind field. All of these are 401.

errorkindMeaning
signature_requiredOne or more of the required signed-request headers (X-Device-Id, X-Device-Key-Id, X-Timestamp, X-Signature) is missing.
unauthorizedbad_signed_headersA device/key id isn't a valid UUID, the timestamp isn't parseable, or the signature isn't valid base64.
unauthorizedclock_skewThe X-Timestamp is outside the allowed skew window. Recoverable — retry after an NTP sync.
unauthorizeddevice_key_revokedThe device key is unknown/revoked, or the user is suspended or deleted. Terminal for the SDK — wipe and re-enroll.
unauthorizedunsupported_key_algThe key's registered algorithm isn't verifiable by this build.
unauthorizedbad_signatureThe signature doesn't verify (against the current key or, during a rotation overlap, the previous key).
unauthorizedreplayed_requestThis exact signed request was already used — a verbatim replay.

Protocol version floor

CodeHTTPMeaning
upgrade_required426The X-Protocol-Version header is absent, non-integer, or below the supported floor. The body carries min_supported and current; the SDK maps this to a force-update state.

Device key rotation (/v1/device/keys/rotate/*)

These are 400 with a specific error code: no_keys_to_rotate, bad_nonce, no_rotation_in_progress, rotation_nonce_expired, rotation_nonce_mismatch, rotation_set_mismatch, bad_new_key_bytes, and bad_new_key_signature. Each message is self-describing.

PIN and registration

CodeHTTPMeaning
pin_invalid401Wrong PIN. The body carries attempts_left.
pin_locked403PIN attempts exhausted, or the code is already locked.
pin_expired410No active PIN, or the PIN's TTL has expired.
cooldown_active429A PIN-resend cooldown is in effect. Carries a Retry-After header.
token_invalid401A registration/signup token is unknown, consumed, or unverified.
token_expired410A registration/signup token is past its TTL.
email_exists409Self-signup on an already-enrolled email.

App attestation

When attestation is enforced, every attestation failure returns 403 with the machine error field forbidden and the message attestation_failed. The specific subreason (nonce mismatch, counter replay, integrity verdict, and so on) is intended for server logs; treat the client-visible failure as opaque and branch only on error: "forbidden" / message: "attestation_failed".


Rate limiting (all surfaces)

Exceeding a rate limit returns 429 with error: "rate_limited", a Retry-After header, and a retry_after_seconds field in the body. See Rate limits for the full policy.


On this page