Authentication
XKOVA has two authentication boundaries: the tenant, proven by an API key, and the member, proven by an identity session. Some actions require a fresh step-up proof on top of either. This page covers the key formats, the three ways to assert a member, and when step-up applies.
Tenant API keys
Every request carries an API key in the Authorization header as a bearer token. A key is
tenant-scoped: it can read and write only the resources its tenant owns.
Authorization: Bearer xkv_test_...
Keys are environment-bound by prefix, so a sandbox key can never act on production data and the reverse:
| Prefix | Environment | Notes |
|---|---|---|
xkv_test_ | Sandbox | Valid only against the sandbox API. Use these while you build. |
xkv_live_ | Production | Valid only after production access is approved for the workspace. |
status: pending_approval with a
pending_approval_request_id, the owner attests it, and re-submitting the same call mints the
key. See Settings and Branding for the console flow and
Policies and Quorum Governance for the seeded baseline.Member identity, three patterns
When a call acts on behalf of a member, XKOVA needs to know which member. Pick the pattern that matches how your system already authenticates members. All three combine with the tenant boundary above, so the platform always knows both the tenant and the acting member.
Pattern A, backend asserts the member
Your backend holds a service key and tells XKOVA which member is acting through an end-user header. This is the right shape for a bank or credit union whose members are already signed in to a digital banking app that your backend speaks to.
Authorization: Bearer xkv_live_...
X-End-User-Id: <account_holder_id>
XKOVA logs, audits, and scopes data access by both the tenant and the asserted member. The end-user header is optional: omit it and the call authenticates the tenant without a specific member, which is the right shape for tenant-scoped operations that no member initiates.
Pattern B, federated XKOVA IDP
For platforms without their own member identity system, members can sign up and sign in directly against the hosted federated XKOVA IDP through the member-auth operations. The flow returns an XKOVA member access token, and the member's device then calls the API with that token as the bearer credential.
Authorization: Bearer <member_access_token>
This path gives you the full XKOVA session lifecycle: refresh rotation, revocation, and per-session rate limits. The sections below cover sign-up, sign-in, and the token lifecycle in full. These flows run in the member's browser, so the Embedded Member guide is the client-side companion to what follows.
Pattern C, bring your own OIDC
If you already run a member-facing OIDC provider (for example Auth0 or Cognito), XKOVA can accept your provider's ID token directly. The tenant is pre-configured with your issuer and client id; XKOVA verifies the token against that issuer and resolves the member.
Authorization: Bearer xkv_live_...
X-OIDC-ID-Token: <jwt_from_your_idp>
X-End-User-Id: <account_holder_id>
You send your provider's ID token on every member call, as shown above. To resolve a member before its first call, JIT-provision the account holder from your provider's subject through the account-holder JIT operation; see Account Holders. The session import operation and the wrapped XKOVA session lifecycle are not available on this path: import accepts a token only when it was issued by XKOVA's own federated identity, so it applies to Pattern B alone.
Member sign-up and sign-in
The XKOVA IDP path (Pattern B) is a set of member-auth operations your member-facing app calls. Every one carries the tenant API key; the session-minting calls return the member access token the device then uses as its bearer credential. These endpoints are rate-limited per operation; see Rate Limits.
Sign up
Create a member with POST /v1/member-auth/sign-up. The body takes email,
password, and an email_confirm_redirect_url, plus optional first_name,
last_name, phone, and user_metadata. The redirect URL must already be
on the tenant's redirect-URL allowlist for the email_confirm purpose (see Browser member-auth
configuration below), or the call is rejected.
The response is one of two shapes. When the tenant requires email confirmation, sign-up returns
status: pending_email_verification with the new account_holder_id and
idp_user_id; the member follows the emailed link and your app calls
POST /v1/member-auth/email/confirm with the token_hash to receive a session.
Otherwise sign-up returns a token set directly.
Sign in
Authenticate a returning member with POST /v1/member-auth/sign-in (email and password). The
response is either a token set or, when the member has a verified second factor, an mfa_required
challenge: status: mfa_required with an mfa_token and the list of enrolled
factors. No access token is issued in that case. Complete the second leg with
POST /v1/member-auth/sign-in/mfa/verify, passing the mfa_token, the chosen
factor_id, and the TOTP code, to receive the token set.
Two passwordless variants issue a session the same way: request then confirm a magic link
(POST /v1/member-auth/sign-in/magic-link/request then .../confirm), and request then
confirm a password reset (POST /v1/member-auth/password-reset/request then
.../confirm). Each request call names a redirect URL that must be allowlisted for its purpose.
Members manage their own TOTP factors through the /v1/member-auth/mfa enroll, verify, list, and
unenroll operations.
The member token set and its lifecycle
Every session-minting call returns the same token set:
| Field | Meaning |
|---|---|
access_token | The bearer credential the member's device sends on each call. |
refresh_token | An opaque, XKOVA-issued handle used to mint a new token set. This is not the underlying identity-provider refresh token. |
token_type | Always bearer. |
expires_in | Seconds until the access token expires. |
session_id | The server-side session this token set belongs to. |
member | The resolved member: account_holder_id, idp_user_id, email, name, phone, and avatar. |
The refresh token XKOVA returns is its own opaque handle; the underlying federated refresh token is held
server-side, so XKOVA rotates and revokes sessions independently of the identity provider. Mint a fresh token
set with POST /v1/member-auth/refresh, which rotates the refresh token as it issues the new
access token. End a session with POST /v1/member-auth/sign-out, and read the current session
with GET /v1/member-auth/session; both require the member access token, not just the tenant
key.
Importing an existing federated session
If a member already holds an XKOVA IDP token pair obtained through the browser sign-in flow, exchange it
for a wrapped XKOVA session once with POST /v1/member-auth/sessions/import. Pass the
access_token and refresh_token; XKOVA verifies the access token's signature,
issuer, and expiry, holds the federated refresh server-side, and returns its own token set. From then on the
member refreshes and signs out through the wrapped operations above.
Session import accepts federated identities only. It verifies the access token was issued by XKOVA's own federated identity and rejects anything else, so a Pattern C bring-your-own-OIDC provider token cannot be imported. Bring-your-own-OIDC members stay on the per-request token model or are resolved through the account-holder JIT operation instead.
Browser member-auth configuration
The Pattern B flows run in the member's browser, so a tenant sets up two allowlists before they work. Manage both from the console under Settings and Branding or through the tenant member-auth operations.
- Redirect-URL allowlist.
GET,POST, andDELETEon/v1/tenant/member-auth/redirect-urls. Each entry pairs apurpose(email_confirm,password_reset, ormagic_link) with a URL. The redirect URL a sign-up, magic-link, or password-reset call names must be on the allowlist for that purpose, or the call is rejected. - Allowed-origins allowlist.
GET,POST, andDELETEon/v1/tenant/member-auth/allowed-origins. Each entry is an exact browser Origin (scheme://host[:port]). A member-auth request whose Origin is not on the list is rejected by the cross-origin guard.
Browser member-auth also derives the member's in-app wallet, which depends on the tenant's provisioned
wallet-provider and identity credentials. Read their metadata with
GET /v1/tenant/custody-secrets: it returns each secret's type, a fingerprint, and its
last-rotated and rotation-due timestamps. The secret material itself is never returned through the API. The
Embedded Member guide walks the browser side of these flows end to end.
Staff and operator sessions
The hosted console authenticates staff with an operator session issued by the XKOVA IDP. Role-gated routes check the staff role behind that session. See Authorization and RBAC for the role model and Roles and Permissions for the full catalog.
Step-up re-auth
Certain high-impact actions require a fresh authentication proof beyond the baseline session. Examples include API-key rotation, webhook secret rotation, staff-role changes, fee-schedule commits, and value transfers above a tenant-configured threshold.
When the session lacks a fresh proof, the API returns 403 with the
step_up_required code and a challenge URL in the error details. Send the caller to the
challenge (a multi-factor or passkey check), then replay the original request with the returned token:
X-Step-Up-Token: <token_from_challenge>
Step-up tokens are short-lived, single-action, and bound to the session that requested them, so they cannot be replayed across sessions or swapped onto a different action. For high-value transactions the token is also bound to the request body.
Authorization header.
If a key is exposed, rotate it immediately; rotation revokes the old key as it issues the replacement.Related
See Authorization and RBAC for what a credential is allowed to do, Account Holders for the member record each identity resolves to, Embedded Member for the browser-side member-auth and wallet flows, Errors and Correlation IDs for the auth error envelope, and the interactive reference for the auth headers each operation accepts.