Skip to content

REST API Reference

All endpoints use JSON request/response bodies. Authentication is via Authorization: Bearer {jwt} where noted.

POST /auth/initiate

Start a new authentication session. Generates an OTP and sends it to the mobile app via FCM push.

Rate limit: 10 requests per minute per IP.

FieldTypeRequiredDescription
tokenIdstringYesVDS token identifier from enrollment
serviceIdstringNoRegistered service identifier
scopesstring[]NoRequested identity scopes
{
"tokenId": "vds-uuid-12345",
"serviceId": "my-web-app",
"scopes": ["identity:name", "identity:age_over_18"]
}
{
"sessionId": "sess_abc123def456",
"autoPassword": "482917",
"wsToken": "hmac-websocket-token",
"random": "a1b2c3d4e5f67890",
"expiresAt": "2025-01-15T10:01:00Z"
}
StatusReason
400Missing or invalid tokenId
403Enrollment revoked
404Enrollment not found
422Invalid scopes for service
429Rate limit exceeded
POST /auth/verify

Verify the mobile app’s OTP confirmation and ECDSA signature. Issues a JWT on success.

FieldTypeRequiredDescription
sessionIdstringYesSession ID from initiation
tokenIdstringYesVDS token identifier
otpstringYes6-digit OTP confirmed by user
signatureBase64stringYesECDSA signature of {sessionId}|{otp}|{timestamp}
timestampnumberYesUnix timestamp (must be within ±30s)
grantedScopesstring[]NoScopes the user chose to grant
{
"sessionId": "sess_abc123def456",
"tokenId": "vds-uuid-12345",
"otp": "482917",
"signatureBase64": "MEUCIQD...",
"timestamp": 1705312860,
"grantedScopes": ["identity:name"]
}
{
"jwt": "eyJhbGciOiJFUzI1NiIs...",
"hash": "hmac-response-verification",
"random": "a1b2c3d4e5f67890",
"expiresAt": "2025-01-15T11:00:00Z"
}
StatusReason
400Invalid request body
401Invalid OTP or signature
404Session not found or expired
429Too many verification attempts (max 3)
POST /enroll

Register a mobile device with a VDS credential. See Enrollment for full details.

Rate limit: 5 requests per hour per IP.

FieldTypeRequiredDescription
vdsDatastringYesEncoded VDS data (Base64/Base45/hex)
publicKeyPemstringYesECDSA P-256 public key (PEM)
deviceIdstringYesUnique device identifier
fcmTokenstringNoFCM push notification token
{
"enrolled": true,
"tokenId": "vds-uuid-from-seal",
"expiresAt": "2026-01-15T00:00:00Z"
}
POST /revoke

Revoke an enrollment. Requires a JWT with idtoken:revoke scope.

Authentication: Required (Authorization: Bearer {jwt})

FieldTypeRequiredDescription
tokenIdstringYesToken ID to revoke
reasonstringYesOne of: lost_device, compromised, expired_document, user_request
{
"revoked": true,
"tokenId": "vds-uuid-12345",
"revokedAt": "2025-01-15T10:30:00Z"
}
GET /health

Returns server health status including dependency checks.

{
"status": "ok",
"version": "1.0.0",
"checks": {
"database": "ok",
"redis": "ok",
"vdsTrust": "ok"
}
}

The status field is "ok" when all checks pass, or "degraded" when one or more dependencies are unhealthy.

GET /.well-known/jwks.json

Returns the server’s public key in JWKS format for JWT verification by relying parties.

{
"keys": [
{
"kty": "EC",
"crv": "P-256",
"kid": "idtoken-server-key-1",
"alg": "ES256",
"use": "sig",
"x": "base64url-x-coordinate",
"y": "base64url-y-coordinate"
}
]
}

Relying parties should fetch this endpoint to verify IDToken JWTs. The kid in the JWT header matches the kid in the JWKS response.

All error responses follow a consistent format:

{
"error": "Error type",
"message": "Human-readable description",
"statusCode": 400
}
EndpointLimit
POST /auth/initiate10 per minute
POST /enroll5 per hour
POST /auth/verify3 attempts per session
Admin endpoints60 per minute

Rate limit headers are included in responses:

X-RateLimit-Limit: 10
X-RateLimit-Remaining: 7
X-RateLimit-Reset: 1705312860