Authentication & SDK Token Generation
AttestID supports two authentication modes, used at different points in your integration:
| Mode | Who uses it | What it sends | Lifetime |
|---|---|---|---|
| API key + client certificate | Your backend | X-API-Key + X-Access-Key-Id headers, over a mutual-TLS connection | Key: until revoked or rotated. Certificate: 365 days |
| SDK token | Web and mobile SDK clients | Authorization: Bearer <sdk_token> | 10 minutes |
API keys are used only for server-to-server calls. Client applications use SDK tokens for every KYC endpoint.
1. API key authentication
Used for account-management endpoints (/v1/account/*), webhook configuration (/v1/webhooks/*), and to generate SDK tokens (POST /v1/kyc/session).
Example headers:
X-API-Key: sk_live_7d0a...b31f
X-Access-Key-Id: ak_live_9f2c...
Both headers are required. The access_key_id must belong to the same key pair as the api_key; a correct secret with someone else's access key ID is rejected.
Requests with invalid, suspended, expired or revoked credentials are rejected with 401.
2. Mutual TLS: a client certificate is required
Every request that carries an API key must also present a client certificate issued by AttestID to your company. This applies to every company, for both test and live keys, and there is no way to turn it off. A request with an API key and no valid certificate gets:
{ "detail": "A valid client certificate is required for API-key requests. It is missing, invalid, revoked, expired, or not issued to this account. Issue one in the dashboard under Client Certificates." }
The certificate must be issued to the same company as the API key. A valid certificate from company A with company B's key is rejected.
SDK-token traffic from browsers and phones is not affected. Only your backend needs a certificate.
In short: create a private key and CSR on your server, issue the certificate in the dashboard under Client Certificates, and attach both files to your HTTP client.
→ Client Certificates (mTLS) has the full steps, examples for Node.js, Python, PHP, Java, C# and Go, a test command, renewal, and troubleshooting.
3. SDK token flow
SDK tokens let browser and mobile apps run KYC without ever holding your API credentials. Your backend generates the token for one specific user.
Step 1: Generate an SDK token from your backend
POST /v1/kyc/session
X-API-Key: sk_live_...
X-Access-Key-Id: ak_live_...
Content-Type: application/json
(+ your client certificate on the TLS connection)
{ "user_id": "user-123" }
Response (201 Created):
{
"sdk_token": "eyJhbGciOi...",
"user_id": "user-123",
"expires_in": 600
}
If you use Node.js, the SDK's createSdkSession() helper makes this call for you, including safe retries:
import { createSdkSession } from '@attestid/sdk';
const session = await createSdkSession(
process.env.ATTESTID_API_URL!,
process.env.ATTESTID_API_KEY!,
process.env.ATTESTID_ACCESS_KEY_ID!,
userId,
{ fetch: fetchWithClientCert }, // a fetch that presents client.crt / client.key
);
Step 2: Return the token to your client app
Your backend returns the sdk_token to your frontend or mobile app, for example as the JSON response of your own /api/attestid-session route (see the SDK guide).
:::warning Resolve the user on your backend
Take user_id from your own authenticated session, not from the request body. If your endpoint trusts whatever userId the browser sends, anyone can mint a token for any user.
:::
Step 3: The SDK uses the token for KYC requests
Authorization: Bearer <sdk_token>
Every /v1/kyc/* endpoint except /kyc/session requires the SDK token, including /kyc/start, /kyc/complete, the liveness endpoints, and result retrieval. These endpoints don't accept an API key.
SDK token rules
SDK tokens:
- Are valid for 10 minutes.
- Are bound to the
user_idgiven when they were generated. A/kyc/startrequest with a differentuser_idis rejected (400), and one user's token can't read another user's verification. - Can't be used to create more tokens, manage keys, or change webhooks.
The SDK refreshes the token through your token callback (getSdkToken) about 15 seconds before it expires, so you don't manage expiry yourself.
4. Token generation with the client SDK
Browser or mobile app
Give the SDK a getSdkToken callback that calls your backend:
const client = new AttestID({
apiUrl: 'https://api.attestid.brimsage.co.ls',
getSdkToken: (userId) =>
fetch('/api/attestid-session', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ userId }),
}).then(r => r.json()),
});
Server mode (Node.js only)
A backend process can hold the API key directly and let the SDK exchange it for tokens. Pass a fetch that presents your client certificate:
const client = new AttestID({
apiUrl: process.env.ATTESTID_API_URL!,
apiKey: process.env.ATTESTID_API_KEY!,
accessKeyId: process.env.ATTESTID_ACCESS_KEY_ID!,
fetch: fetchWithClientCert,
});
The SDK refuses this configuration anywhere other than a real Node.js process (browser, React Native, edge runtimes) and throws INSECURE_CONFIG, because a bundler would ship the key to every visitor.
Other tokens
| Token | Lifetime | Used for |
|---|---|---|
| Company dashboard session | 8 hours | Dashboard login. Not used by the SDK |
| SDK token | 10 minutes | All /v1/kyc/* calls from the client |
Dashboard and SDK tokens are typed: one kind can't be presented where another is expected.
Summary diagram
┌─────────────┐ X-API-Key + X-Access-Key-Id ┌──────────────┐
│ Your backend│ + client certificate (mTLS) │ POST /kyc/ │
│ (holds │ ─────────────────────────────────▶│ session │
│ api_key, │ └──────┬───────┘
│ client.key)│ ◀──────────── sdk_token (10 min) ─────────┘
└─────┬───────┘
│ hands sdk_token to client (your own API route)
▼
┌─────────────┐ Authorization: Bearer <sdk_token> ┌──────────────┐
│ Browser / │ ─────────────────────────────────▶ │ /kyc/start │
│ mobile app │ │ liveness │
│ (@attestid/ │ ◀────── signed verification result │ /kyc/complete│
│ sdk) │ └──────────────┘
└─────────────┘