Overview
SparkVault supports two authentication methods:
| Method | Header | Best For |
|---|---|---|
| API Key | X-API-Key |
Server-to-server integrations, automation, CI/CD pipelines |
| JWT Token | Authorization: Bearer |
User-facing applications, browser sessions |
For most integrations, API keys are the simplest choice. Use JWT tokens only if you're building a user-facing application that needs to manage individual user sessions.
API Key Authentication
API keys provide simple, persistent authentication for server-side integrations. Create an API key from the
API Keys page and include it in the X-API-Key header.
curl https://api.sparkvault.com/v1/sparks \
-H "X-API-Key: sv_live_abc123xyz789..."
API Key Format
API keys follow a consistent format:
sv_live_...: Production keys (live data)
API keys grant full access to your account. Never expose them in client-side code, public repositories, or logs.
If a key is compromised, revoke it immediately from the API Keys page.
Example: Creating a Spark with an API key
curl -X POST https://api.sparkvault.com/v1/sparks \
-H "X-API-Key: sv_live_abc123xyz789..." \
-H "Content-Type: application/json" \
-d '{
"payload": "super_secret_password_123"
}'
Managing API Keys Programmatically
API keys can be managed in the app at
app.sparkvault.com/api/keys, or programmatically with the
endpoints below. All three endpoints require authentication (JWT or API key). Creating and revoking keys
additionally require an admin or owner role. Non-admin users receive 403 FORBIDDEN.
/v1/api-keys
Create a new API key. Requires an admin or owner role. The full key string is returned once and is never retrievable again.
Request Body
| Parameter | Type | Required | Description |
|---|---|---|---|
name |
string | Required | Display name identifying the key's purpose (max 100 characters). |
expires_in_days |
integer | Optional | Days until the key expires (1-3650). Omit for a non-expiring key. |
Response Fields
| Field | Type | Description |
|---|---|---|
api_key_id |
string | Unique key identifier (key_...). Use this id to revoke the key. |
api_key |
string | The full API key (sv_live_...). Shown only in this response. Store it securely. |
key_preview |
string | Masked preview for display (e.g. sv_live_ab...wxyz). |
name |
string | The key's display name. |
created_at |
integer | Creation time (Unix epoch seconds). |
expires_at |
integer | Expiration time (Unix epoch seconds), or null if the key does not expire. |
warning |
string | Reminder that the key will not be shown again. |
Example
Requestcurl -X POST https://api.sparkvault.com/v1/api-keys \
-H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..." \
-H "Content-Type: application/json" \
-d '{
"name": "CI/CD pipeline",
"expires_in_days": 90
}'
{
"data": {
"api_key_id": "key_abc123...",
"api_key": "sv_live_abc123xyz789...",
"key_preview": "sv_live_ab...z789",
"name": "CI/CD pipeline",
"created_at": 1783036800,
"expires_at": 1790812800,
"warning": "Store this API key securely. It will not be shown again."
}
}
/v1/api-keys
List the account's API keys with cursor-based pagination. Key strings are never returned, only masked previews.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
limit |
integer | Optional | Maximum keys per page (1-100).Default: 50 |
cursor |
string | Optional | Pagination cursor from a previous response's next_cursor. |
Response Fields
| Field | Type | Description |
|---|---|---|
api_keys |
array | Key objects: api_key_id, name, key_preview, status (active | expired | revoked), created_at, last_used_at, expires_at, revoked_at. |
count |
integer | Number of keys in this page. |
has_more |
boolean | Whether more pages are available. |
next_cursor |
string | Cursor for the next page. Present only when has_more is true. |
active |
integer | Number of active keys in this page. |
/v1/api-keys/:id
Revoke an API key by its api_key_id. Requires an admin or owner role. Idempotent: revoking an already-revoked key succeeds and returns its original revocation time.
Response Fields
| Field | Type | Description |
|---|---|---|
api_key_id |
string | The revoked key's identifier. |
name |
string | The key's display name. Returned only on first revocation. When the key was already revoked, the response omits name and includes a message field instead. |
status |
string | Always revoked. |
revoked_at |
integer | Revocation time (Unix epoch seconds). |
JWT Token Authentication
JWT tokens are used for user session management in browser-based applications. SparkVault uses the Identity Product as an OIDC provider for user authentication. After successful authentication via Identity, you'll receive SparkVault session tokens.
curl https://api.sparkvault.com/v1/sparks \
-H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..."
Token Types
| Type | Lifetime | Purpose |
|---|---|---|
| Access Token | 1 hour | Short-lived token for API requests |
| Refresh Token | 30 days | Single-use token to obtain new access tokens (rotated on every refresh) |
User Authentication Flow
SparkVault uses an OIDC (OpenID Connect) flow with the Identity Product for user authentication. This provides passwordless login via passkeys, magic links, social login, and more.
Flow Overview
- Initiate Login: Redirect user to Identity Product with PKCE challenge
- User Authenticates: Via passkey, magic link, or social login
- Callback: Identity Product redirects back with authorization code
- Token Exchange: Exchange code for SparkVault session tokens
- Registration (New Users): Complete profile setup if needed
For detailed OIDC integration instructions, see the Identity Product documentation. The SparkVault web app uses Identity Product for all user authentication.
Session Endpoints
/v1/auth/identity/token
Exchange an OIDC authorization code from Identity Product for SparkVault session tokens. This is called after the user completes authentication via Identity Product.
Request Body
| Parameter | Type | Required | Description |
|---|---|---|---|
code |
string | Required | Authorization code from Identity Product callback (max 512 characters). |
code_verifier |
string | Required | PKCE code verifier that must match the code_challenge sent to Identity Product. 43-128 characters, per RFC 7636. |
Response (Existing User)
| Field | Type | Description |
|---|---|---|
access_token |
string | JWT access token (1 hour lifetime) |
refresh_token |
string | JWT refresh token (30 day lifetime) |
user |
object | User profile information |
account |
object | Account information |
Response (New User)
| Field | Type | Description |
|---|---|---|
access_token |
string | Identity-only JWT (limited access) |
refresh_token |
string | Identity-only refresh token |
user |
null | null indicates registration required |
account |
null | null indicates registration required |
Example
Requestcurl -X POST https://api.sparkvault.com/v1/auth/identity/token \
-H "Content-Type: application/json" \
-d '{
"code": "auth_code_from_identity_product",
"code_verifier": "your_pkce_code_verifier"
}'
{
"data": {
"access_token": "eyJhbGciOiJSUzI1NiIs...",
"refresh_token": "eyJhbGciOiJSUzI1NiIs...",
"user": {
"user_id": "usr_abc123...",
"email": "user@example.com",
"name": "John Doe",
"role": "admin"
},
"account": {
"account_id": "acc_xyz789...",
"organization_name": "Acme Corp",
"status": "active"
}
}
}
/v1/auth/identity/verify
Directly verify an Identity Product JWT token without using the OIDC redirect flow. Useful for XHR-based authentication where redirect flows are not practical.
Request Body
| Parameter | Type | Required | Description |
|---|---|---|---|
token |
string | Required | JWT token received from Identity Product verification |
Response
| Field | Type | Description |
|---|---|---|
access_token |
string | JWT access token (1 hour lifetime) |
refresh_token |
string | JWT refresh token (30 day lifetime) |
user |
object | User profile (null if registration required) |
account |
object | Account information (null if registration required) |
Example
Requestcurl -X POST https://api.sparkvault.com/v1/auth/identity/verify \
-H "Content-Type: application/json" \
-d '{"token": "eyJhbGciOiJFZDI1NTE5..."}'
{
"data": {
"access_token": "eyJhbGciOiJSUzI1NiIs...",
"refresh_token": "eyJhbGciOiJSUzI1NiIs...",
"user": {
"user_id": "usr_abc123...",
"email": "user@example.com",
"name": "John Doe",
"role": "admin"
},
"account": {
"account_id": "acc_xyz789...",
"organization_name": "Acme Corp",
"status": "active"
}
}
}
Use this endpoint when you're using the Identity Product SDK in XHR mode (without redirects). The SDK will return a JWT token directly after verification, which you can exchange for SparkVault session tokens using this endpoint.
/v1/auth/complete-signup
Complete registration for new users. Requires an identity-only JWT (from token exchange with user: null). Creates the account and upgrades to full session tokens.
Request Body
| Parameter | Type | Required | Description |
|---|---|---|---|
organization_name |
string | Required | Name of the organization/company (1-255 characters) |
full_name |
string | Optional | User's display name (up to 255 characters) |
Response
| Field | Type | Description |
|---|---|---|
access_token |
string | Full JWT access token |
refresh_token |
string | Full JWT refresh token |
user |
object | Created user profile |
account |
object | Created account object |
This endpoint requires an identity-only JWT in the Authorization header. The JWT proves email ownership via the Identity Product verification.
Signup returns 403 Forbidden if the email's domain is already claimed by another
organization. The user must be invited by that organization's admin instead.
/v1/auth/refresh
Exchange a refresh token for a new access token and a new refresh token. Use this when your access token expires.
Request Body
| Parameter | Type | Required | Description |
|---|---|---|---|
refresh_token |
string | Required | Valid refresh token |
Response
| Field | Type | Description |
|---|---|---|
access_token |
string | New JWT access token |
refresh_token |
string | New rotated refresh token. Replace your stored token |
token_type |
string | Always "Bearer" |
expires_in |
integer | Token lifetime in seconds |
Example
Requestcurl -X POST https://api.sparkvault.com/v1/auth/refresh \
-H "Content-Type: application/json" \
-d '{"refresh_token": "eyJhbGciOiJSUzI1NiIs..."}'
{
"data": {
"access_token": "eyJhbGciOiJSUzI1NiIs...",
"refresh_token": "eyJhbGciOiJSUzI1NiIs...",
"token_type": "Bearer",
"expires_in": 3600
}
}
Refresh tokens are one-time-use. Every call to /v1/auth/refresh revokes
the presented token and returns a new refresh_token. Always replace your stored token
with the one in the response. Reusing an already-rotated token fails with 401 AUTHENTICATION_ERROR;
if two requests race with the same token, the loser fails with 401 TOKEN_REPLAY. In either
case, discard stored tokens and sign the user in again.
/v1/auth/logout
Revoke a refresh token. Requires authentication. Returns 204 No Content on success.
Request Body
| Parameter | Type | Required | Description |
|---|---|---|---|
refresh_token |
string | Required | Refresh token to revoke |
Example
Requestcurl -X POST https://api.sparkvault.com/v1/auth/logout \
-H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..." \
-H "Content-Type: application/json" \
-d '{"refresh_token": "eyJhbGciOiJSUzI1NiIs..."}'
(204 No Content)
/v1/auth/viewer-token
Generate a short-lived viewer token for cross-domain direct-access viewing on x.sv. Requires authentication. Takes no request body.
Response
| Field | Type | Description |
|---|---|---|
viewer_token |
string | Short-lived JWT for the x.sv viewer (5 minute lifetime) |
expires_in |
integer | Token lifetime in seconds, always 300 |
Vault Access Tokens (VAT)
Vault Access Tokens are special, short-lived tokens required for reading and writing data in encrypted vaults. They are obtained by "unsealing" a vault with its Vault Master Key (VMK).
| Property | Value |
|---|---|
| Header | X-Vault-Access-Token |
| Lifetime | 1 hour (default), up to 24 hours |
| Scope | Single vault only |
| Revocation | Automatic on expiry, or manual via seal operation |
/v1/vaults/:id/unseal
Unseal a vault with its Vault Master Key to obtain a Vault Access Token.
Request Body
| Parameter | Type | Required | Description |
|---|---|---|---|
vmk |
string | Required | The Vault Master Key. Also accepts a dvak_ token (Delegated Vault Access Key) in place of the raw VMK. |
ttl_seconds |
integer | Optional | VAT lifetime in seconds (1-86400).Default: 3600 |
Response Fields
| Field | Type | Description |
|---|---|---|
vat |
string | The Vault Access Token (vat_...). Send it in the X-Vault-Access-Token header. |
vault_id |
string | The unsealed vault's id. |
issued_at |
integer | Issue time (Unix epoch seconds). |
expires_at |
integer | Expiration time (Unix epoch seconds). |
ttl_seconds |
integer | Effective VAT lifetime in seconds. |
warning |
string | Reminder to store the VAT securely. |
# First, unseal the vault to get a VAT
curl -X POST https://api.sparkvault.com/v1/vaults/vlt_abc123/unseal \
-H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..." \
-H "Content-Type: application/json" \
-d '{"vmk": "YOUR_VAULT_MASTER_KEY"}'
# Then use the VAT for ingot operations
curl https://api.sparkvault.com/v1/vaults/vlt_abc123/ingots \
-H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..." \
-H "X-Vault-Access-Token: vat_xyz789..."
- Obtain a VAT only when you need to access vault contents
- Store VATs securely in memory, never persist to disk
- VATs are vault-specific. Each vault requires its own VAT.
- Consider sealing vaults when done to immediately invalidate VATs
Authentication Errors
Error Responses
| Status | Code | Description |
|---|---|---|
| 400 | VALIDATION_ERROR |
Missing or invalid request parameters |
| 401 | AUTHENTICATION_ERROR |
Invalid credentials, expired access token, invalid or revoked refresh token, or suspended account |
| 401 | TOKEN_REPLAY |
Refresh token was consumed by a concurrent rotation. Sign in again |
| 403 | FORBIDDEN |
Insufficient permissions: e.g. identity-only token on a protected endpoint (complete registration first), or admin role required |
| 429 | RATE_LIMIT_EXCEEDED |
Too many requests |
Security Best Practices
API Keys
- Generate separate API keys for each integration or service
- Use descriptive names to identify key purpose
- Rotate keys periodically (every 90 days recommended)
- Revoke keys immediately if compromised
- Never commit keys to version control. Use environment variables.
JWT Tokens
- Store access tokens in memory only (not localStorage)
- Implement automatic token refresh before expiry
- Persist the rotated refresh token from every refresh response. The old one is immediately revoked
- Clear tokens on logout and tab close
- Handle 401 errors by redirecting to login
PKCE Security
- Always use S256 code challenge method (never plain)
- Generate cryptographically random code verifiers (32+ bytes)
- Store PKCE parameters in sessionStorage (not localStorage)
- Validate the state parameter to prevent CSRF attacks
General
- Always use HTTPS. Never send credentials over plain HTTP.
- Implement proper error handling for auth failures
- Log authentication events for security monitoring
- Use passkeys where possible for phishing resistance