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

POST/api/v1/auth/passkey/authenticate/begin

Initiate a passkey authentication ceremony. Returns a challenge and the list of allowed credentials for the WebAuthn API.

Authentication:No Auth Required

Code Examples

curl -X POST https://api.orbai.world/api/v1/auth/passkey/authenticate/begin \
  -H "Content-Type: application/json"

Response

200Authentication challenge created. Pass these options to the WebAuthn browser API (navigator.credentials.get()).
{
  "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

POST/api/v1/auth/passkey/authenticate/finish

Complete the passkey authentication ceremony by submitting the signed challenge from the WebAuthn API. Returns JWT tokens on success.

Authentication:No Auth Required

Request Parameters

ParameterTypeRequiredDescription
session_idstring RequiredThe session ID returned from the begin endpoint.
credential_idstring RequiredThe credential ID from the WebAuthn assertion response.
sign_countinteger RequiredThe signature counter from the authenticator data.
device_idstringOptionalUnique device identifier.
platformstringOptionalClient 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

200Passkey authentication successful. Returns the standard AuthResponse with user profile, JWT tokens, and subscription.
{
  "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
  }
}
401Authentication failed. The challenge response is invalid or the session has expired.
{
  "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

POST/api/v1/security/passkeys/register/begin

Initiate a passkey registration ceremony. Returns a challenge and options for the WebAuthn API to create a new credential.

Authentication:Bearer Token

Code Examples

curl -X POST https://api.orbai.world/api/v1/security/passkeys/register/begin \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."

Response

200Registration challenge created. Pass these options to navigator.credentials.create().
{
  "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

POST/api/v1/security/passkeys/register/finish

Complete the passkey registration ceremony by submitting the new credential data from the WebAuthn API.

Authentication:Bearer Token

Request Parameters

ParameterTypeRequiredDescription
session_idstring RequiredThe session ID returned from the begin registration endpoint.
credential_idstring RequiredThe base64url-encoded credential ID from the WebAuthn create response.
public_keystring RequiredThe base64url-encoded public key from the attestation response.
namestringOptionalA 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

200Passkey registered successfully.
{
  "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

GET/api/v1/security/passkeys

Retrieve all passkeys registered to the authenticated user's account.

Authentication:Bearer Token

Code Examples

curl https://api.orbai.world/api/v1/security/passkeys \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."

Response

200List of all registered passkeys.
{
  "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

PUT/api/v1/security/passkeys/{passkeyID}

Update the display name of a registered passkey.

Authentication:Bearer Token

Request Parameters

ParameterTypeRequiredDescription
passkeyIDstring RequiredThe passkey ID (path parameter). Example: pk_abc123.
namestring RequiredThe 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

200Passkey renamed successfully.
{
  "success": true,
  "data": {
    "id": "pk_abc123",
    "name": "Work MacBook Touch ID",
    "updated_at": "2026-02-08T17:00:00Z"
  }
}

Delete Passkey

DELETE/api/v1/security/passkeys/{passkeyID}

Remove a registered passkey from the account. This action cannot be undone.

Authentication:Bearer Token

Request Parameters

ParameterTypeRequiredDescription
passkeyIDstring RequiredThe 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

200Passkey deleted successfully.
{
  "success": true,
  "data": {
    "message": "Passkey deleted successfully."
  }
}
404The passkey ID does not exist or does not belong to this user.
{
  "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

1

Begin authentication

Call POST /api/v1/auth/passkey/authenticate/begin to get a challenge and allowed credentials.

2

Browser ceremony

Pass the server response to navigator.credentials.get() to trigger the browser's passkey UI (biometric prompt, security key tap, etc.).

3

Finish authentication

Send the signed assertion to POST /api/v1/auth/passkey/authenticate/finish to receive JWT tokens.

Registration Flow

1

Begin registration

While logged in, call POST /api/v1/security/passkeys/register/begin to get registration options.

2

Create credential

Pass the server response to navigator.credentials.create() to create a new passkey on the user's device.

3

Finish registration

Send the new credential data to POST /api/v1/security/passkeys/register/finish to save the passkey.