Device Trust & MFA API Endpoints
Register hardware fingerprints, dispatch MFA verification codes, verify devices, list trusted hardware, and revoke compromised devices.
Device Trust & MFA API Endpoints
The Device Trust API enforces Zero-Trust Hardware Quarantine by evaluating hardware fingerprints, dispatching time-bounded email verification codes, and promoting verified devices to trusted status. These endpoints work together to ensure that even a compromised master password cannot be exploited from unauthorized hardware.
1. Check Device Trust Status
POST /api/auth/device-check
Submits hardware fingerprint signals for a given user and returns whether the device is already trusted or requires MFA verification.
Rate Limit
| Window | Maximum Requests | Scope |
|---|---|---|
| 60 seconds | 20 | Per IP address |
Request Headers
Content-Type: application/jsonRequest Body Schema
| Field | Type | Required | Description |
|---|---|---|---|
userId | string | Yes | The authenticated user's unique identifier. |
signals | object | Yes | Hardware fingerprint signals object (see below). |
signals Object Schema
| Field | Type | Required | Description |
|---|---|---|---|
clientDeviceUUID | string | No | Persistent UUID generated and stored in the client's localStorage. Highest priority identifier when present. |
userAgent | string | No | Browser navigator.userAgent string. |
language | string | No | Browser navigator.language value (e.g., en-US). |
screenResolution | string | No | Display dimensions (e.g., 1920x1080). |
timezone | string | No | IANA timezone identifier (e.g., Africa/Johannesburg). |
platform | string | No | Operating system platform (e.g., macOS, Win32). |
Code Examples
curl -X POST "https://passwordmanager.vertueal.com/api/auth/device-check" \
-H "Content-Type: application/json" \
-d '{
"userId": "usr_01j8m2k9p3x4y5z6",
"signals": {
"clientDeviceUUID": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)...",
"language": "en-US",
"screenResolution": "2560x1440",
"timezone": "Africa/Johannesburg",
"platform": "macOS"
}
}'const response = await fetch(
"https://passwordmanager.vertueal.com/api/auth/device-check",
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
userId: "usr_01j8m2k9p3x4y5z6",
signals: {
clientDeviceUUID: localStorage.getItem("clientDeviceUUID") ?? undefined,
userAgent: navigator.userAgent,
language: navigator.language,
screenResolution: `${screen.width}x${screen.height}`,
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
platform: navigator.platform,
},
}),
}
);
const result = await response.json();
if (result.verified) {
// Device is trusted — proceed to vault unlock
} else {
// Device requires MFA — trigger /api/auth/mfa/send
}Success Responses
Device Already Trusted (200 OK):
{
"verified": true,
"deviceId": "client-a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"message": "Device verified"
}Device Quarantined — MFA Required (200 OK):
{
"verified": false,
"deviceId": "client-a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"reason": "Device pending verification",
"requiresMfa": true
}Error Responses
| Status | Body | Cause |
|---|---|---|
400 | { "error": "Invalid request data", "details": {...} } | Request body failed Zod schema validation (e.g., missing userId). |
429 | { "error": "Too many requests. Please try again later." } | Exceeded 20 requests per 60-second window. |
500 | { "error": "Internal Server Error" } | Server-side failure (e.g., database or Fingerbank API error). |
Note
Device Fingerprint Priority: When a clientDeviceUUID is provided, it is used as the primary device identifier (client-{uuid}). If absent, the server queries the Fingerbank API for hardware profiling. If Fingerbank is unavailable, a fallback Base64 hash of local signals is computed.
2. Send MFA Verification Code
POST /api/auth/mfa/send
Generates a random 6-digit verification code, stores it with a 5-minute TTL, and dispatches it to the user's registered email address via SMTP.
Rate Limit
| Window | Maximum Requests | Scope |
|---|---|---|
| 60 seconds | 3 | Per IP address |
Request Body Schema
| Field | Type | Required | Description |
|---|---|---|---|
email | string | Yes | The user's registered email address. Must be a valid email format. |
Code Examples
curl -X POST "https://passwordmanager.vertueal.com/api/auth/mfa/send" \
-H "Content-Type: application/json" \
-d '{ "email": "user@example.com" }'await fetch("https://passwordmanager.vertueal.com/api/auth/mfa/send", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email: "user@example.com" }),
});Success Response (200 OK)
{
"success": true,
"message": "Code sent"
}Error Responses
| Status | Body | Cause |
|---|---|---|
400 | { "error": "Invalid email" } | Email field missing or fails format validation. |
429 | { "error": "Too many codes sent. Try again later." } | Exceeded 3 code dispatches per 60-second window. |
500 | { "error": "Failed to send code" } | SMTP delivery failure or database error. |
Info
Verification codes expire after 5 minutes (300 seconds). If the code is not used within this window, a new one must be requested. Previous unused codes for the same email are automatically overwritten.
3. Verify MFA Code & Promote Device
POST /api/auth/mfa/verify
Validates the 6-digit verification code against the stored OTP record and, if correct, promotes the device from quarantined to trusted status. Also triggers a New Device Login security alert email.
Rate Limit
| Window | Maximum Requests | Scope |
|---|---|---|
| 60 seconds | 3 | Per IP address |
Request Body Schema
| Field | Type | Required | Description |
|---|---|---|---|
userId | string | Yes | The authenticated user's unique identifier. |
userEmail | string | Yes | The user's registered email address. |
deviceId | string | Yes | The deviceId returned by the /api/auth/device-check endpoint. |
code | string | Yes | The 6-digit verification code from the user's email. Must be exactly 6 characters. |
Code Examples
curl -X POST "https://passwordmanager.vertueal.com/api/auth/mfa/verify" \
-H "Content-Type: application/json" \
-d '{
"userId": "usr_01j8m2k9p3x4y5z6",
"userEmail": "user@example.com",
"deviceId": "client-a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"code": "849201"
}'const response = await fetch(
"https://passwordmanager.vertueal.com/api/auth/mfa/verify",
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
userId: "usr_01j8m2k9p3x4y5z6",
userEmail: "user@example.com",
deviceId: deviceIdFromCheckResponse,
code: userEnteredCode, // 6-digit string
}),
}
);
if (response.ok) {
// Device is now trusted — proceed to unlock vault
}Success Response (200 OK)
{
"success": true
}Note
Upon successful verification, the system automatically dispatches a New Device Login security alert email to the user's registered address, containing the device name, IP address, and geographic location.
Error Responses
| Status | Body | Cause |
|---|---|---|
400 | { "error": "Invalid or expired code" } | Code does not match, has already been consumed, or has expired (5-minute TTL). |
400 | { "error": "Invalid data" } | Request body failed Zod validation (e.g., code not exactly 6 digits). |
429 | { "error": "Too many attempts" } | Exceeded 3 verification attempts per 60-second window. |
500 | { "error": "Verification failed" } | Internal server error. |
4. List Trusted Devices
GET /api/devices
Returns all registered devices for a given user, sorted by most recently active.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
userId | string | Yes | The authenticated user's unique identifier. |
Code Examples
curl -X GET "https://passwordmanager.vertueal.com/api/devices?userId=usr_01j8m2k9p3x4y5z6"const response = await fetch(
`https://passwordmanager.vertueal.com/api/devices?userId=${userId}`
);
const { devices } = await response.json();
devices.forEach((device) => {
console.log(`${device.device_name} — ${device.is_verified ? "Trusted" : "Quarantined"}`);
});Success Response (200 OK)
{
"devices": [
{
"_id": "66e3f8a1b2c3d4e5f6789012",
"user_id": "usr_01j8m2k9p3x4y5z6",
"device_fingerprint_hash": "client-a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"device_name": "Mozilla/5.0 (Macintosh; In...",
"is_verified": true,
"ip_address": "203.0.113.195",
"location": "Cape Town, South Africa",
"isp": "Vodacom",
"os": "macOS",
"last_used_at": "2026-09-20T18:30:00.000Z",
"created_at": "2026-09-15T10:00:00.000Z"
},
{
"_id": "66e3f8a1b2c3d4e5f6789013",
"user_id": "usr_01j8m2k9p3x4y5z6",
"device_fingerprint_hash": "client-b2c3d4e5-f6a7-8901-bcde-f12345678901",
"device_name": "Mozilla/5.0 (iPhone; CPU ...",
"is_verified": true,
"ip_address": "198.51.100.42",
"location": "Johannesburg, South Africa",
"isp": "MTN",
"os": "iOS",
"last_used_at": "2026-09-19T14:22:00.000Z",
"created_at": "2026-09-10T08:15:00.000Z"
}
]
}Error Responses
| Status | Body | Cause |
|---|---|---|
400 | { "error": "Missing userId" } | The userId query parameter was not provided. |
500 | { "error": "Failed to fetch devices" } | Internal server error during database query. |
5. Revoke a Trusted Device
DELETE /api/devices
Permanently removes a device from the user's trusted device list. Any future login from the revoked hardware will be quarantined and require full MFA verification again.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
userId | string | Yes | The authenticated user's unique identifier. |
deviceHash | string | Yes | The device_fingerprint_hash of the device to revoke. |
Code Examples
curl -X DELETE "https://passwordmanager.vertueal.com/api/devices?userId=usr_01j8m2k9p3x4y5z6&deviceHash=client-b2c3d4e5-f6a7-8901-bcde-f12345678901"await fetch(
`https://passwordmanager.vertueal.com/api/devices?userId=${userId}&deviceHash=${deviceHash}`,
{ method: "DELETE" }
);Success Response (200 OK)
{
"success": true
}Warning
Device revocation is immediate and irreversible. The revoked device's trust token is permanently invalidated. Anyone currently signed in on that hardware will be locked out upon their next vault sync and must complete full MFA verification to regain access.
Error Responses
| Status | Body | Cause |
|---|---|---|
400 | { "error": "Missing parameters" } | Either userId or deviceHash query parameter was not provided. |
500 | { "error": "Delete failed" } | Internal server error during database deletion. |