SenseCrypt Docs

Changelog

Release notes for SenseCrypt — how the product is versioned and where notable changes are recorded.

Notable changes to SenseCrypt are recorded here.

How we version

SenseCrypt exposes a versioned HTTP API — the endpoint paths are prefixed (for example /v1/...), and the current surface is described in the API reference. Breaking changes to a released API version are avoided; where behavior needs to change incompatibly, it is introduced under a new version. Entries are grouped by release, newest first. Unreleased holds what is merged and awaiting a release — when that release is cut, the heading is renamed to its version and dated, so a dated heading is always something you can run. Earlier releases collects the entries that predate those version headings.

Unreleased

Implicit and hybrid sign-ins carry sid in the first id_token

An application registered for a non-code response type and a back-channel logout URL received an id_token without the sid claim on the first sign-in of a browser session; only a later silent re-authorization carried it. The claim is now there from the first sign-in, so the Logout Token your endpoint receives when that session ends names a session you were told about. Applications on the code flow were never affected, and sid is still omitted for an application that registers no back-channel logout URL. A sign-in refused at its last step — the user lost access to the application, or a requested scope was unbound or a requested API audience detached while the sign-in was in progress — now reaches your redirect URI as a standard error response (error=access_denied or invalid_scope, with your state) rather than a bare error response shown in the browser tab that your application never learned about. See Tokens and sessions and Relying party.

Application registration rules answer 422 with a field and a code — breaking for direct API callers

Every field-level refusal on the Management API now uses one envelope: 422 with details[], each entry naming the offending field and a stable rule code (fapi.requires_pkce, fapi_ciba.requires_signing_keys, jwks.private_material, immutable_field, extra_forbidden, …) — documented under Management API validation errors. On POST and PATCH /v1/admin/oidc-apps this replaces 24 refusals that were 400 bad_request with a prose message (the FAPI 2.0/CIBA registration rules, the mutual TLS and JWK Set checks, the CIBA delivery-mode rules, the refresh-token rotation rules, and the redirect-URI rules among them); the same rule now returns the same code on create and on update. Two further changes apply to every management body: an unknown field is refused (422, extra_forbidden) where it used to be silently ignored, and a field that is fixed at creation (client_type, token_endpoint_auth_method, billing_model, a tenant's slug or fapi_profile) is refused as immutable_field instead of being dropped. An integrator that branched on 400 as "business rule, show the user" versus 422 as "malformed payload" must read details[].code for both; successful responses are unchanged.

Tenant security profile set at creation; browser-session lifetime moves to the Issuer endpoint

A tenant's security profile (fapi_profile: Standard or FAPI 2.0/CIBA) is chosen when the tenant is created and cannot be changed afterwards; discovery is derived from it and every application in a FAPI tenant is held to it. The OP browser-session lifetime (op_session_ttl_seconds) is set on PATCH /v1/admin/issuer (capability issuer:update), alongside a read view of what discovery advertises and why. PATCH /v1/admin/tenants/{id} is rename-only and refuses both fields with the 422 validation envelope — immutable_field for fapi_profile, field_moved for op_session_ttl_seconds (see Management API validation errors). Neither field existed on the previous release, so no caller was setting them; the console uses the new surfaces. See Managing tenants.

Hybrid response types (per-application, off by default)

An application can now be registered for the OIDC hybrid response types — code id_token, code token and code id_token token — alongside code and the implicit types. The code flow remains the default and the recommended flow; a request for a type the application is not registered for is refused with unsupported_response_type, and an application on the FAPI 2.0 profile stays code-only. A hybrid response returns the authorization code and the front-channel material together in the URL fragment (or as a form_post); the code is still redeemed at the token endpoint with PKCE, a nonce is required for every hybrid type except code token, and the front-channel id_token binds the code with c_hash (and the access token with at_hash when one is returned). Redeeming a code twice revokes every token issued off it — the front-channel access token included — and signing the user out of your application, or suspending, deleting or renaming the user, ends the front-channel access tokens issued to it. Discovery now lists all six response types. See OIDC & OAuth 2.0, the validation recipe for the c_hash check, and the error codes.

Implicit response types and form_post (per-application, off by default)

An application can now be registered for the OIDC implicit response types — id_token and id_token token — alongside (or instead of) code, and any response can be delivered with response_mode=form_post. The code flow remains the default and the recommended flow; a request for a type the application is not registered for is refused with unsupported_response_type. Implicit responses ride the URL fragment (never the query), require a nonce, issue no refresh token, and bind the access token to the id_token with at_hash — see OIDC & OAuth 2.0, the validation recipe for the nonce / at_hash checks, and the error codes. Discovery now lists response_modes_supported.

CIBA request validation and callback contract — breaking

Two CIBA request rules changed incompatibly, and the callback behaviour is now documented as a contract.

  • binding_message is capped at 140 displayable characters (was 512) and refused with a new error code. The message is counted after Unicode NFC normalisation and must be plain text — control characters, line breaks and bidirectional formatting controls are refused; letters in any script, emoji and their joiner sequences are accepted (unassigned code points, such as a newer emoji, are no longer refused). A message that breaks the rule now returns invalid_binding_message (CIBA Core §13) instead of invalid_request. Clients that sent longer messages, or matched on invalid_request for this case, must adjust. See CIBA and the error codes.
  • client_notification_token is validated. It is required for ping and push delivery and, whenever supplied, must be a bearer token as RFC 6750 defines one (letters, digits, -._~+/, optional trailing =; no spaces or line breaks) of at most 1024 characters; anything else is invalid_request. Previously any non-empty value was accepted.
  • A signed authentication request (request JWT) is single-use. Its jti is remembered until the object expires; presenting the same object twice is invalid_request.
  • Callback contract for ping/push clients (now documented): a 3xx or 4xx from your notification endpoint is final — never retried, a redirect never followed — and for a push client it loses the approved authorization; 5xx and transport failures are retried up to 5 times in total. A refused request is notified to ping and push clients alike; an expired request is notified to push clients only (a ping client learns of the expiry from its own poll, which answers expired_token). An approval that lands in the last seconds of the request window is still delivered.
  • Push delivery is unavailable to FAPI-profile clients; a FAPI-profile issuer advertises backchannel_token_delivery_modes_supported: ["poll", "ping"].

FAPI 2.0 Security Profile and Message Signing

An application can be registered on the FAPI 2.0/CIBA security profile, and a tenant can be created so that every application is held to it. What the profile brings:

  • Sender-constrained tokens. DPoP is available to every client — send a proof, get back token_type: "DPoP" and an access token carrying cnf.jkt. Where discovery publishes mtls_endpoint_aliases, RFC 8705 mutual TLS is available too: the tls_client_auth and self_signed_tls_client_auth client-authentication methods and certificate-bound tokens (cnf["x5t#S256"]). Where the document does not publish the aliases, those methods and certificate binding are not available on that deployment. Introspection reports cnf and token_type.
  • Signed requests and responses. A signed request object (JAR) is accepted at the PAR endpoint only/authorize answers request_not_supported for a request parameter and request_uri_not_supported for a non-PAR request_uri, and discovery says request_parameter_supported: false. JARM signs the authorization response itself: response_mode jwt, query.jwt, fragment.jwt and form_post.jwt return a single response JWT, errors included.
  • Profile rules at runtime. A FAPI application must push its authorization request, is code-only, authenticates with an asymmetric method, demonstrates its sender constraint on every token request, and gets authorization codes capped at 60 seconds.
  • A new protected resource. /v1/idp/oidc/resource is the issuer's own resource server: present an access token (Bearer or DPoP) and it answers the token's client_id, sub, scope, aud, exp, iat and token_type.
  • The client_credentials grant for a registered application, opt-in per application (allow_client_credentials, off by default). Not a breaking change: no registered OIDC application could mint through that grant before this release. The contract — what the flag gates, what the token carries, and what it is refused for — is on OIDC & OAuth 2.0 → Grant types.

New registration rules are refused as 422 entries with their own codes (fapi.*, fapi_ciba.*, jar.*, jwks.*, mtls.*). See OIDC & OAuth 2.0 and the error codes.

FAPI-CIBA: signed backchannel authentication requests

A CIBA client can send its authorization parameters as a signed request JWT at /bc-authorize, and a FAPI-profile client (or one registered with require_signed_request_object) must — a plain parameter request from such a client is invalid_request. The object's iss, aud, exp, iat, nbf and jti are all required, the jti is single-use, and discovery advertises the accepted algorithms as backchannel_authentication_request_signing_alg_values_supported. See CIBA.

Back-channel logout, with per-application initiators

An application that registers a backchannel_logout_uri now chooses which session endings send it a logout token (backchannel_logout_initiators). The vocabulary is six values. rp-logout is always on — registering the URI is that opt-in. The other five each default off, so no application is told about an ending it never asked about: session-revoked (a suspend, a SCIM active:false, or another user signing in on the same browser), access-revoked (the user lost access to this application through an authorization change — removed from a group that granted it, console or SCIM; the group deleted; or the group detached from the application), account-deleted, email-identifier-changed and session-expired. A list without rp-logout, or with an unknown member, is refused 422 (backchannel_logout_initiators.requires_rp_logout / .invalid). The authorization-change ending is the one whose behaviour is also new: losing an application through a group change already cut that application's refresh-token families, and now tells the application too — one logout token per live browser session of the user's that had signed in to it — while a user left in no app-attached group has their OP browser session ended as well, with every opted-in application in its sign-in list told. Device keys and passkeys are untouched either way; see Groups & access. Every logout token names the one session that ended with its sid — the OP never sends a sub-only token — and is typed logout+jwt and signed with the application's registered id_token algorithm. Discovery advertises backchannel_logout_supported and backchannel_logout_session_supported. The receiving-side checks are on the Relying party page.

OP browser session, prompt, max_age, RP-initiated logout, RS256 ID tokens and the claims parameter

  • An OP browser session (the sc_op_session cookie) is established by the face ceremony. While it is live a second application on the same tenant can be authorized without another ceremony. Its lifetime is absolute from the last ceremony — 8 hours by default, per-tenant on PATCH /v1/admin/issuer, and 0 turns browser sessions off entirely.
  • prompt and max_age now mean something. prompt=none is answered silently from that session or refused with login_required; login, consent and select_account force a fresh ceremony. max_age (and an application's default_max_age) is evaluated at /authorize, never at the token exchange. display and ui_locales are accepted and ignored.
  • RP-Initiated Logout ends the browser session and revokes the user's refresh-token families for every application that session signed in to. With a verified id_token_hint you are redirected to a registered post_logout_redirect_uri; without one the user confirms and lands on SenseCrypt's own signed-out page. GET and POST are both accepted.
  • ID tokens can be RS256 per application (id_token_signed_response_alg, ES256 by default) — a second per-tenant RSA key is created the first time one is needed, rotation covers both algorithms, and discovery advertises ["ES256", "RS256"]. Access tokens stay ES256. Anywhere the docs used to say "the id_token is an ES256 JWT", read "the algorithm your application registered".
  • The OIDC Core §5.5 claims request parameter is honoured at /authorize and PAR (claims_parameter_supported: true); it reshapes a release within the scopes your application may request and never widens one. The per-application id_token_includes_scope_claims switch (default on) decides whether scope-released profile claims ride in the ID token or only at UserInfo.
  • Protocol shape. /authorize accepts GET and POST; duplicate query parameters are refused; UserInfo speaks the RFC 6750 challenge on GET and POST (see the error codes); redeeming an authorization code a second time revokes every token that code's first use issued.

An id_token_hint must be an ID token — security

Every JWT a tenant signs verifies against the same JWKS, so signature and issuer alone used to let an access token or a logout token stand in for an ID token wherever a hint is accepted. A hint is now verified as an ID token on both halves of the JWS: the JOSE typ must be JWT (so logout+jwt, an at+jwt and a missing typ are all refused) and the payload must carry neither token_use nor events. A client that passed anything but a real ID token gets the 400 refusal page at /logout, invalid_request at /authorize and unknown_user_id at /bc-authorize; a genuine ID token, expired included, is unaffected. events is now a reserved claim name. A new attribute or claim-map output by that name is refused with a 422; an attribute that predates the gate is silently dropped — from every ID token, every UserInfo response and every SAML assertion — with no error raised, so a relying party that consumed the claim simply stops receiving it. Rename the attribute. See Customize claims and scopes.

Earlier releases

Passkeys and live-person sign-in (FIDO2/WebAuthn)

SenseCrypt sign-in is now built on real FIDO2/WebAuthn passkeys (ES256). Every sign-in pairs a device-bound passkey, which proves the device, with a live-face check, which proves the person. Three sign-in methods are available, all invisible to your OIDC/SAML integration:

  • Simple QR — scan an on-screen QR, then a face scan in the SenseCrypt Authenticator app, matched on the device.
  • Passkeys — a FIDO2/WebAuthn passkey through a roaming-authenticator app. This is the phishing-resistant path: WebAuthn binds each assertion to its origin, so a credential proven to one site can't be replayed against a look-alike.
  • Simple Webcam (enterprise only) — a webcam face scan on a trusted customer network, matched on the workstation rather than a phone. Available to enterprise customers; contact sales@seventhsense.ai.

SenseCrypt still never stores your face image or a biometric template, only a sealed, unlinkable, non-reversible token derived from your face that even we cannot reverse, and which contains no PII. See How SenseCrypt works and the Passkey entry in the glossary.

Initial documentation release

The first public release of the SenseCrypt documentation, covering:

On this page