Passkeys (WebAuthn)
Passwordless authentication using FIDO2/WebAuthn passkeys for secure, phishing-resistant login.
Passkeys (WebAuthn / FIDO2)
Passkeys provide passwordless, phishing-resistant authentication using the WebAuthn standard. Users can authenticate with biometrics (Touch ID, Face ID), hardware security keys (YubiKey), or platform authenticators built into their device.
This page covers both public authentication endpoints (no auth required) and protected management endpoints (bearer auth required).
Authenticate with Passkey
Begin Authentication
/api/v1/auth/passkey/authenticate/beginInitiate a passkey authentication ceremony. Returns a challenge and the list of allowed credentials for the WebAuthn API.
Code Examples
curl -X POST https://api.orbai.world/api/v1/auth/passkey/authenticate/begin \
-H "Content-Type: application/json"Response
{
"success": true,
"data": {
"challenge": "dGhpcyBpcyBhIGNoYWxsZW5nZQ...",
"timeout": 60000,
"rpId": "orbvpn.com",
"allowCredentials": [
{
"id": "Y3JlZGVudGlhbC1pZC0x...",
"type": "public-key",
"transports": ["internal", "hybrid"]
}
],
"userVerification": "preferred",
"session_id": "sess_abc123"
}
}Finish Authentication
/api/v1/auth/passkey/authenticate/finishComplete the passkey authentication ceremony by submitting the signed challenge from the WebAuthn API. Returns JWT tokens on success.
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
session_id | string | Required | The session ID returned from the begin endpoint. |
credential_id | string | Required | The credential ID from the WebAuthn assertion response. |
sign_count | integer | Required | The signature counter from the authenticator data. |
device_id | string | Optional | Unique device identifier. |
platform | string | Optional | Client platform. One of: ios, android, windows, macos, linux, web. |
Code Examples
curl -X POST https://api.orbai.world/api/v1/auth/passkey/authenticate/finish \
-H "Content-Type: application/json" \
-d '{
"session_id": "sess_abc123",
"credential_id": "Y3JlZGVudGlhbC1pZC0x...",
"sign_count": 5,
"device_id": "550e8400-e29b-41d4-a716-446655440000",
"platform": "web"
}'Responses
{
"success": true,
"data": {
"user": {
"id": 1,
"uuid": "usr_abc123",
"username": "john_doe",
"email": "user@example.com",
"role": "USER",
"active": true
},
"tokens": {
"access_token": "eyJhbGciOiJIUzI1NiIs...",
"refresh_token": "dGhpcyBpcyBhIHJlZnJlc2...",
"access_token_expires_at": "2026-02-09T12:00:00Z",
"refresh_token_expires_at": "2026-03-08T12:00:00Z",
"token_type": "Bearer"
},
"subscription": {
"plan_name": "Premium",
"status": "active",
"expires_at": "2026-12-31T23:59:59Z"
},
"requires_2fa": false
}
}{
"success": false,
"error": {
"code": "PASSKEY_AUTH_FAILED",
"message": "Passkey authentication failed. The challenge may have expired or the credential is invalid."
}
}Register a Passkey
These endpoints require bearer authentication. The user must already be logged in to register a new passkey on their account.
Begin Registration
/api/v1/security/passkeys/register/beginInitiate a passkey registration ceremony. Returns a challenge and options for the WebAuthn API to create a new credential.
Code Examples
curl -X POST https://api.orbai.world/api/v1/security/passkeys/register/begin \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."Response
{
"success": true,
"data": {
"challenge": "cmVnaXN0cmF0aW9uLWNoYWxsZW5nZQ...",
"rp": {
"name": "OrbVPN",
"id": "orbvpn.com"
},
"user": {
"id": "dXNlci1pZC0x...",
"name": "user@example.com",
"displayName": "John Doe"
},
"pubKeyCredParams": [
{ "type": "public-key", "alg": -7 },
{ "type": "public-key", "alg": -257 }
],
"timeout": 60000,
"session_id": "sess_reg_xyz789"
}
}Finish Registration
/api/v1/security/passkeys/register/finishComplete the passkey registration ceremony by submitting the new credential data from the WebAuthn API.
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
session_id | string | Required | The session ID returned from the begin registration endpoint. |
credential_id | string | Required | The base64url-encoded credential ID from the WebAuthn create response. |
public_key | string | Required | The base64url-encoded public key from the attestation response. |
name | string | Optional | A human-readable name for this passkey, e.g. "MacBook Touch ID" or "YubiKey 5". |
Code Examples
curl -X POST https://api.orbai.world/api/v1/security/passkeys/register/finish \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
-H "Content-Type: application/json" \
-d '{
"session_id": "sess_reg_xyz789",
"credential_id": "Y3JlZGVudGlhbC1pZC0x...",
"public_key": "cHVibGljLWtleS1kYXRh...",
"name": "MacBook Touch ID"
}'Responses
{
"success": true,
"data": {
"id": "pk_abc123",
"credential_id": "Y3JlZGVudGlhbC1pZC0x...",
"name": "MacBook Touch ID",
"created_at": "2026-02-08T16:00:00Z",
"last_used_at": null
}
}List Passkeys
/api/v1/security/passkeysRetrieve all passkeys registered to the authenticated user's account.
Code Examples
curl https://api.orbai.world/api/v1/security/passkeys \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."Response
{
"success": true,
"data": {
"passkeys": [
{
"id": "pk_abc123",
"credential_id": "Y3JlZGVudGlhbC1pZC0x...",
"name": "MacBook Touch ID",
"created_at": "2026-01-15T10:30:00Z",
"last_used_at": "2026-02-08T09:15:00Z"
},
{
"id": "pk_def456",
"credential_id": "Y3JlZGVudGlhbC1pZC0y...",
"name": "YubiKey 5",
"created_at": "2026-02-01T14:20:00Z",
"last_used_at": "2026-02-07T18:45:00Z"
}
]
}
}Rename Passkey
/api/v1/security/passkeys/{passkeyID}Update the display name of a registered passkey.
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
passkeyID | string | Required | The passkey ID (path parameter). Example: pk_abc123. |
name | string | Required | The new display name for the passkey. |
Code Examples
curl -X PUT https://api.orbai.world/api/v1/security/passkeys/pk_abc123 \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
-H "Content-Type: application/json" \
-d '{
"name": "Work MacBook Touch ID"
}'Response
{
"success": true,
"data": {
"id": "pk_abc123",
"name": "Work MacBook Touch ID",
"updated_at": "2026-02-08T17:00:00Z"
}
}Delete Passkey
/api/v1/security/passkeys/{passkeyID}Remove a registered passkey from the account. This action cannot be undone.
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
passkeyID | string | Required | The passkey ID (path parameter). Example: pk_abc123. |
Code Examples
curl -X DELETE https://api.orbai.world/api/v1/security/passkeys/pk_abc123 \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."Responses
{
"success": true,
"data": {
"message": "Passkey deleted successfully."
}
}{
"success": false,
"error": {
"code": "PASSKEY_NOT_FOUND",
"message": "The specified passkey was not found."
}
}Notes
Browser Support
Passkeys are supported in Chrome 108+, Safari 16+, Firefox 122+, and Edge 108+. On mobile, passkeys work with iOS 16+ and Android 9+ (with Google Play Services). Always provide a fallback authentication method for unsupported browsers.
Cross-Device Authentication
Modern passkey implementations support cross-device authentication via Bluetooth. A user can authenticate on a desktop browser by scanning a QR code with their phone, even if the passkey is stored on the phone.
Passkey Deletion
Deleting a passkey from OrbVPN does not remove it from the user's device or password manager. The passkey will still appear in their device's credential list but will no longer work for authentication with OrbVPN.
Authentication Flow
Begin authentication
Call POST /api/v1/auth/passkey/authenticate/begin to get a challenge and allowed credentials.
Browser ceremony
Pass the server response to navigator.credentials.get() to trigger the browser's passkey UI (biometric prompt, security key tap, etc.).
Finish authentication
Send the signed assertion to POST /api/v1/auth/passkey/authenticate/finish to receive JWT tokens.
Registration Flow
Begin registration
While logged in, call POST /api/v1/security/passkeys/register/begin to get registration options.
Create credential
Pass the server response to navigator.credentials.create() to create a new passkey on the user's device.
Finish registration
Send the new credential data to POST /api/v1/security/passkeys/register/finish to save the passkey.
Related Endpoints
- Login -- Email/password authentication
- Two-Factor Authentication -- TOTP-based 2FA
- OAuth Login -- Social provider authentication