Skip to content

Credential Verification

The credential verification API provides a single endpoint for validating any VeraID-issued credential at runtime. Use it to authenticate non-human identities at your API gateway, within a service mesh, or as part of custom authentication middleware.

Verification Endpoint

Endpoint: POST /api/v1/credentials/verify

The verification endpoint accepts a credential value and returns its validity status along with the associated identity and credential metadata.

Request

FieldTypeRequiredDescription
credentialstringYesThe full credential value (e.g., kd_live_abc...)
Terminal window
curl -X POST https://app.veraid.io/api/v1/credentials/verify \
-H "Content-Type: application/json" \
-d '{
"credential": "kd_live_aB3cD4eF5gH6iJ7kL8mN9oP0qR1sT2u"
}'

Response: Valid Credential

When the credential is valid, the response includes the identity and credential metadata needed to make authorization decisions downstream.

{
"valid": true,
"identity": {
"id": "idt_3a1f8c29-b7d4-4e2a-9c8f-1d5e7a2b4c6d",
"name": "payment-processor",
"type": "SERVICE_ACCOUNT",
"status": "ACTIVE",
"riskScore": 12,
"tags": ["production", "pci-scope"],
"metadata": {
"team": "payments",
"environment": "production"
}
},
"credential": {
"id": "crd_9f24d67e-a1b3-4c5d-8e7f-2a3b4c5d6e7f",
"type": "API_KEY",
"status": "ACTIVE",
"scopes": ["identities:read", "credentials:read"],
"expiresAt": "2026-06-19T00:00:00Z",
"usageCount": 1424,
"usageLimit": 10000
}
}

Response: Invalid Credential

When the credential is invalid, expired, revoked, or does not exist, the response indicates failure without disclosing the specific reason to prevent information leakage.

{
"valid": false,
"identity": null,
"credential": null
}

Verification Checks

When a credential is submitted for verification, VeraID performs the following checks in order. The credential is rejected if any check fails.

  1. Existence — The credential hash matches a record in the database
  2. Status — The credential status is ACTIVE (not REVOKED, EXPIRED, or ROTATED past its grace period)
  3. Identity status — The associated identity is ACTIVE (not SUSPENDED or REVOKED)
  4. Expiration — The current time is before the credential’s expiresAt timestamp
  5. Usage limit — The credential’s usageCount has not exceeded its usageLimit
  6. IP allowlist — If the identity has allowedIPs configured, the request source IP must match
  7. Origin allowlist — If the identity has allowedOrigins configured, the request Origin header must match

Use Cases

API Gateway Middleware

Place the verification endpoint at the entry point of your API to authenticate all incoming NHI requests before they reach your application layer.

// Express middleware example
import { Request, Response, NextFunction } from "express";
async function verifyCredential(
req: Request,
res: Response,
next: NextFunction
) {
const authHeader = req.headers.authorization;
if (!authHeader?.startsWith("Bearer kd_")) {
return res.status(401).json({ error: "Missing or invalid credential" });
}
const credential = authHeader.replace("Bearer ", "");
const response = await fetch(
"https://app.veraid.io/api/v1/credentials/verify",
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ credential }),
}
);
const result = await response.json();
if (!result.valid) {
return res.status(401).json({ error: "Invalid credential" });
}
// Attach identity and credential metadata to the request
req.identity = result.identity;
req.credential = result.credential;
next();
}

Service Mesh Validation

In a service mesh architecture, use the verification endpoint as an external authorization service. Each service validates incoming credentials before processing requests, ensuring that compromised services cannot make unauthorized lateral calls.

// Sidecar proxy authorization check
async function authorizeRequest(credential: string, requiredScopes: string[]) {
const response = await fetch(
"https://app.veraid.io/api/v1/credentials/verify",
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ credential }),
}
);
const result = await response.json();
if (!result.valid) {
return { authorized: false, reason: "Invalid credential" };
}
// Check that the credential has all required scopes
const hasScopes = requiredScopes.every((scope) =>
result.credential.scopes.includes(scope)
);
if (!hasScopes) {
return { authorized: false, reason: "Insufficient scopes" };
}
// Check risk score threshold
if (result.identity.riskScore >= 75) {
return { authorized: false, reason: "Identity risk score too high" };
}
return { authorized: true, identity: result.identity };
}

Custom Auth Middleware

Build custom authentication flows that combine VeraID credential verification with your own authorization logic.

// Next.js API route middleware
import { NextRequest, NextResponse } from "next/server";
export async function middleware(req: NextRequest) {
const credential = req.headers.get("x-api-key");
if (!credential) {
return NextResponse.json(
{ error: "API key required" },
{ status: 401 }
);
}
const verifyResponse = await fetch(
"https://app.veraid.io/api/v1/credentials/verify",
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ credential }),
}
);
const result = await verifyResponse.json();
if (!result.valid) {
return NextResponse.json(
{ error: "Invalid API key" },
{ status: 401 }
);
}
// Forward identity context to downstream handlers
const headers = new Headers(req.headers);
headers.set("x-identity-id", result.identity.id);
headers.set("x-identity-type", result.identity.type);
headers.set("x-identity-risk-score", String(result.identity.riskScore));
headers.set("x-credential-scopes", result.credential.scopes.join(","));
return NextResponse.next({ headers });
}

Performance Considerations

The verification endpoint is optimized for high-throughput, low-latency authentication.

MetricValue
Average latency< 15ms (p50), < 50ms (p99)
Rate limit10,000 requests/second per tenant
CachingCredential hashes cached in Redis for sub-millisecond lookups
Availability99.99% SLA

Error Responses

Status CodeMeaning
200Verification completed (check valid field for result)
400Malformed request body or missing credential field
429Rate limit exceeded
500Internal verification error (retry with backoff)

What’s Next