Skip to main content

Authentication

The platform uses three credential types. A secret key (dv_sk_…) holds all permissions and lives on your server. A session token (dv_tok_…) is short-lived, scoped to one end user, and safe to ship to a mobile or browser client. A public key (dv_pk_…) identifies your tenant and mode in a client SDK and grants nothing on its own.

What each credential can call​

CredentialCan call
Secret key (dv_sk_…)Every endpoint.
Session token (dv_tok_…) or publishable key (dv_pk_…)POST /v1/ocr (without capture_integrity), POST /v1/fraud/detect (the end-user view), POST /v1/face/verify, POST /v1/liveness/check, POST /v1/liveness/challenges, GET /v1/ping, GET /v1/features and, for a token, its own GET /v1/verifications/{vf_id}.

Everything else (reading, listing or deleting stored results, the face gallery, PATCH /v1/features/{name}, /v1/plan, /v1/usage and DELETE /v1/sessions/{jti}) answers 403 forbidden to a session token or publishable key: call it from your server with the secret key.

Every request also carries a Drukverify-Version header naming the wire format it expects. The SDKs send 2026-05-12; the gateway also accepts 2026-04-26. A missing or unknown value is a 400 (missing_version_header, unknown_version).

Secret keys (dv_sk_…)​

Create them on the dashboard's API keys page. Treat them like passwords. They authenticate every server-side request and have full tenant authority.

curl -H "Authorization: Bearer dv_sk_test_..." \
-H "Drukverify-Version: 2026-05-12" \
https://api.drukverify.com/v1/ping

Rotate from the same page: create the new key, update your servers, then revoke the old one. Revocation is immediate.

Session tokens (dv_tok_…)​

Short-lived JWTs minted by POST /v1/sessions with a secret key, signed by the gateway, scoped to one customer_ref. Ship these to clients.

curl -X POST https://api.drukverify.com/v1/sessions \
-H "Authorization: Bearer dv_sk_live_..." \
-H "Drukverify-Version: 2026-05-12" \
-H "Content-Type: application/json" \
-d '{"customer_ref":"user_42","ttl_seconds":1800}'
FieldNotes
customer_refYour user id, 1 to 255 characters, opaque to the platform. Carried into results, webhooks and the audit log.
ttl_secondsOptional, 60 to 3600, default 1800. Tokens cannot be renewed; mint a fresh one when the previous expires.
scopesOptional list. Not enforced yet; what a token can call is fixed (see the table above).

The response carries token, jti (for DELETE /v1/sessions/{jti}), expires_at, scopes and mode. The token's mode matches the key that minted it. The SDKs treat the token as opaque; only the prefix is meaningful to a client.

A token minted by POST /v1/verifications is additionally bound to that verification, so the checks made with it become its steps. See Verification sessions.

Mobile flow (Flutter)​

The app never sees dv_sk_*. It is configured with the public key and a tokenProvider callback that fetches a fresh dv_tok_* from your backend:

final client = EkycClient(
config: EkycConfig(
host: 'https://api.drukverify.com',
apiKey: 'dv_pk_live_…',
tokenProvider: () async {
final res = await Dio().get<Map<String, dynamic>>(
'https://my-backend.example.com/session',
);
return res.data!['token'] as String;
},
),
);

The SDK calls tokenProvider lazily on the first request, caches the token, and on a 401 calls the provider again and retries the request once.

Browser flow (JavaScript)​

Same shape: your backend exchanges the secret key for a session token and hands it to the page, which constructs the client with the token as apiKey. See JS install.

Don'ts​

  • Don't embed dv_sk_* in mobile or browser code. Anyone who decompiles the binary or opens DevTools can extract it.
  • Don't reuse a token across users. Mint one per user session.
  • Don't send tokens over email or chat. They are for request-scoped HTTPS only.