PVPipe Authentication API Reference

This document provides complete API reference for the PVPipe Authentication microservice, including standard authentication, biometric authentication, device management, and push notifications.

Base Information

Base URL: https://auth.pvpipe.com (production), http://localhost:8080 (development) API Version: v1 Authentication: Bearer tokens (JWT)

Response Format

All endpoints return responses in this standard format:

Success Response

{
  "data": {
    // Response data varies by endpoint
  }
}

Error Response

{
  "message": "Error description",
  "statusCode": 400
}

Authentication Types

The API supports multiple authentication patterns:

Pattern Header Use Cases
Standard Authentication Authorization: Bearer <access_token> Web applications, device management
Biometric Authentication Authorization: Bearer <biometric_access_token> Mobile biometric login, confirmations
Public Endpoints None required Device registration verification, mobile login
Internal Services Authorization: Bearer <service_token> Service-to-service communication

Rate Limiting

Endpoint Category Limit Window Burst
Authentication 10/min 1 hour 20
Device Registration 5/min 15 min 10
Confirmation 20/min 1 hour 50
Device Management 30/min 1 hour 60

Standard Authentication

Login

Endpoint: POST /api/v1/auth/login Authentication: None (public)

Request

{
  "email": "[email protected]",
  "password": "userpassword"
}

Response

{
  "data": {
    "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "accessTokenExpiresAt": "2025-08-02T23:30:00Z",
    "refreshTokenExpiresAt": "2025-08-05T15:30:00Z"
  }
}

Token Refresh

Endpoint: POST /api/v1/auth/refresh Authentication: None (uses refresh token)

Request

{
  "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}

Response

Same format as login endpoint.

Logout

Endpoint: POST /api/v1/auth/logout Authentication: Required

Request

{
  "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}

Device Management

List User Devices

Endpoint: GET /api/v1/auth/devices Authentication: Required

Response

{
  "data": {
    "devices": [
      {
        "id": "123e4567-e89b-12d3-a456-426614174000",
        "deviceName": "John's iPhone 15 Pro",
        "deviceType": "mobile",
        "deviceFingerprint": "iOS-17.1-A17Pro-TouchID-12345",
        "isActive": true,
        "lastUsedAt": "2025-08-02T14:30:00Z",
        "createdAt": "2025-07-15T10:30:00Z",
        "updatedAt": "2025-08-02T14:30:00Z"
      }
    ]
  }
}

Delete Device

Endpoint: DELETE /api/v1/auth/devices/{deviceId} Authentication: Required

Response

{
  "data": {
    "success": true,
    "message": "Device deleted successfully"
  }
}

Update Device FCM Token

Endpoint: PUT /api/v1/auth/devices/fcm-token Authentication: Required

Request

{
  "deviceId": "123e4567-e89b-12d3-a456-426614174000",
  "fcmToken": "fGzJ8F2B3xF9ZqR8V3Rm7KzQj8F2B3xF9ZqR8V3Rm7KzQj8F2B3xF9ZqR8V3Rm7"
}

Response

{
  "data": {
    "success": true,
    "message": "FCM token updated successfully"
  }
}

Device Registration

Create Registration Challenge

Endpoint: POST /api/v1/auth/devices/register/challenge Authentication: Required

Request

{
  "deviceName": "John's iPhone 15 Pro",
  "deviceType": "mobile",
  "deviceFingerprint": "iOS-17.1-A17Pro-TouchID-12345",
  "publicKey": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE...",
  "keyAlgorithm": "ES256"
}

Field Validation

  • deviceName: 1-255 characters, alphanumeric + spaces, hyphens, apostrophes
  • deviceType: One of mobile, desktop, tablet
  • deviceFingerprint: Unique device identifier (max 255 chars)
  • publicKey: PEM-formatted public key (max 10KB)
  • keyAlgorithm: One of ES256, RS256, PS256

Response

{
  "data": {
    "challenge": "Zm9vYmFyYmF6cXV4dGVzdGNoYWxsZW5nZWFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6",
    "expiresAt": "2025-08-02T15:35:00Z",
    "deviceId": "123e4567-e89b-12d3-a456-426614174000",
    "sessionId": "987fcdeb-51a2-43d7-8f9e-123456789abc"
  }
}

Error Responses

  • 400 Bad Request: Invalid request body or validation errors
  • 401 Unauthorized: Missing or invalid authentication token
  • 409 Conflict: Device already registered for this user

Verify Device Registration

Endpoint: POST /api/v1/auth/devices/register/verify Authentication: Required

Request

{
  "sessionId": "987fcdeb-51a2-43d7-8f9e-123456789abc",
  "signedChallenge": "MEUCIQDKzQj8F2B3xF9ZqR8V3Rm7..."
}

Response

{
  "data": {
    "success": true,
    "deviceId": "123e4567-e89b-12d3-a456-426614174000",
    "device": {
      "id": "123e4567-e89b-12d3-a456-426614174000",
      "deviceName": "John's iPhone 15 Pro",
      "deviceType": "mobile",
      "deviceFingerprint": "iOS-17.1-A17Pro-TouchID-12345",
      "isActive": true,
      "lastUsedAt": null,
      "createdAt": "2025-08-02T15:30:00Z",
      "updatedAt": "2025-08-02T15:30:00Z"
    }
  }
}

Biometric Authentication

Mobile Biometric Login

Create Authentication Challenge

Endpoint: POST /api/v1/auth/mobile/challenge Authentication: None (public)

Request
{
  "deviceFingerprint": "iOS-17.1-A17Pro-TouchID-12345"
}
Response
{
  "data": {
    "challenge": "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY3ODkw",
    "expiresAt": "2025-08-02T15:32:00Z",
    "sessionId": "456e7890-f12b-34c5-d678-901234567def"
  }
}

Complete Biometric Authentication

Endpoint: POST /api/v1/auth/mobile/biometric Authentication: None (public)

Request
{
  "sessionId": "456e7890-f12b-34c5-d678-901234567def",
  "signedChallenge": "MEUCIQDKzQj8F2B3xF9ZqR8V3Rm7...",
  "rememberMe": true
}
Response
{
  "data": {
    "success": true,
    "tokens": {
      "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
      "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
      "accessTokenExpiresAt": "2025-08-02T16:45:00Z",
      "refreshTokenExpiresAt": "2025-09-01T15:30:00Z"
    }
  }
}
Biometric Access Token Claims
{
  "id": 12345,
  "email": "[email protected]",
  "employee": {
    "id": "EMP001",
    "name": "John Doe",
    "avatarFileId": "file_123"
  },
  "department": {
    "id": "DEPT001",
    "name": "Engineering"
  },
  "permissions": ["document.read", "document.create"],
  "token_use": "biometric_access",
  "device_id": "123e4567-e89b-12d3-a456-426614174000",
  "auth_method": "biometric",
  "trust_level": "high",
  "session_id": "456e7890-f12b-34c5-d678-901234567def"
}

Refresh Biometric Tokens

Endpoint: POST /api/v1/auth/mobile/refresh Authentication: None (uses refresh token)

Request
{
  "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
Response

Same format as biometric authentication endpoint.

Biometric Confirmation

Initiate Confirmation

Endpoint: POST /api/v1/auth/confirmation/initiate Authentication: Required

Request

{
  "actionType": "payment_approval",
  "actionPayload": {
    "amount": 50000,
    "currency": "VND",
    "recipient": "Nguyen Van A",
    "bankAccount": "VCB-123456789",
    "description": "Payment for services"
  }
}

Supported Action Types

Action Type Description Required Payload Fields
payment_approval Financial transaction approval amount, currency, recipient
document_approval Document signing/approval documentId, documentName
purchase_order Purchase order approval amount, supplier, items
user_access User access grant/modification userId, permissions
settings_change System settings modification settingKey, oldValue, newValue
password_change Password modification userId
device_register New device registration deviceName, deviceType
sensitive_data_access Access to sensitive data dataType, reason

Response

{
  "data": {
    "confirmationId": "conf_789e0123-f45b-67c8-d901-234567890abc",
    "challenge": "cXVlc3Rpb25uYWlyZWNoYWxsZW5nZWFiY2RlZmdoaWprbG1ub3A=",
    "expiresAt": "2025-08-02T15:35:00Z"
  }
}

Get Confirmation Status

Endpoint: GET /api/v1/auth/confirmation/{id}/status Authentication: Required

Response

{
  "data": {
    "confirmationId": "conf_789e0123-f45b-67c8-d901-234567890abc",
    "status": "pending",
    "actionType": "payment_approval",
    "actionPayload": {
      "amount": 50000,
      "currency": "VND",
      "recipient": "Nguyen Van A"
    },
    "createdAt": "2025-08-02T15:30:00Z",
    "expiresAt": "2025-08-02T15:40:00Z",
    "updatedAt": "2025-08-02T15:30:00Z"
  }
}

Status Values

  • pending: Waiting for user confirmation
  • approved: User confirmed with biometric signature
  • rejected: User explicitly rejected
  • expired: Confirmation window expired

Verify Confirmation

Endpoint: POST /api/v1/auth/confirmation/{id}/verify Authentication: Required

Request

{
  "deviceId": "123e4567-e89b-12d3-a456-426614174000",
  "signedChallenge": "MEUCIQDKzQj8F2B3xF9ZqR8V3Rm7..."
}

Response

{
  "data": {
    "success": true,
    "confirmationId": "conf_789e0123-f45b-67c8-d901-234567890abc",
    "status": "approved"
  }
}

Reject Confirmation

Endpoint: POST /api/v1/auth/confirmation/{id}/reject Authentication: Required

Request

{
  "reason": "Suspicious activity detected"
}

Response

{
  "data": {
    "success": true,
    "confirmationId": "conf_789e0123-f45b-67c8-d901-234567890abc",
    "status": "rejected"
  }
}

Internal/Service Endpoints

Token Verification

Endpoint: GET /internal/verify Authentication: Service token or request token

Headers

Authorization: Bearer <token_to_verify>
X-Service-Name: document-service

Response

{
  "valid": true,
  "claims": {
    "id": 12345,
    "email": "[email protected]",
    "permissions": ["document.read"],
    "token_use": "biometric_access",
    "device_id": "device-uuid",
    "trust_level": "high"
  }
}

Health Check

Endpoint: GET /health Authentication: None

Response

{
  "status": "healthy",
  "timestamp": "2025-08-02T15:30:00Z",
  "version": "1.0.0",
  "services": {
    "database": "healthy",
    "redis": "healthy",
    "firebase": "healthy"
  },
  "uptime": 86400
}

WebAuthn/Passkey Support

Register WebAuthn Credential

Endpoint: POST /api/v1/auth/webauthn/register/begin Authentication: Required

Request

{
  "userVerification": "preferred",
  "authenticatorSelection": {
    "residentKey": "preferred",
    "userVerification": "preferred"
  }
}

Response

{
  "data": {
    "challengeId": "webauthn_challenge_uuid",
    "publicKey": {
      "challenge": "base64-challenge",
      "rp": {
        "name": "PVPipe",
        "id": "pvpipe.com"
      },
      "user": {
        "id": "base64-user-id",
        "name": "[email protected]",
        "displayName": "John Doe"
      },
      "pubKeyCredParams": [
        {"type": "public-key", "alg": -7},
        {"type": "public-key", "alg": -257}
      ],
      "timeout": 300000,
      "attestation": "none"
    }
  }
}

Complete WebAuthn Registration

Endpoint: POST /api/v1/auth/webauthn/register/finish Authentication: Required

Request

{
  "challengeId": "webauthn_challenge_uuid",
  "credential": {
    "id": "credential-id",
    "rawId": "base64-raw-id",
    "type": "public-key",
    "response": {
      "attestationObject": "base64-attestation",
      "clientDataJSON": "base64-client-data"
    }
  }
}

WebAuthn Login

Endpoint: POST /api/v1/auth/webauthn/login/begin Authentication: None

Request

{
  "email": "[email protected]"
}

Response

{
  "data": {
    "challengeId": "webauthn_login_challenge_uuid",
    "publicKey": {
      "challenge": "base64-challenge",
      "timeout": 300000,
      "rpId": "pvpipe.com",
      "allowCredentials": [
        {
          "type": "public-key",
          "id": "base64-credential-id"
        }
      ],
      "userVerification": "preferred"
    }
  }
}

Complete WebAuthn Login

Endpoint: POST /api/v1/auth/webauthn/login/finish Authentication: None

Request

{
  "challengeId": "webauthn_login_challenge_uuid",
  "credential": {
    "id": "credential-id",
    "rawId": "base64-raw-id",
    "type": "public-key",
    "response": {
      "authenticatorData": "base64-auth-data",
      "clientDataJSON": "base64-client-data",
      "signature": "base64-signature"
    }
  }
}

Response

Same format as standard login (returns JWT tokens).

Error Codes

HTTP Status Codes

  • 200 OK: Request successful
  • 400 Bad Request: Invalid request format or parameters
  • 401 Unauthorized: Authentication required or invalid
  • 403 Forbidden: Insufficient permissions
  • 404 Not Found: Resource not found
  • 409 Conflict: Resource conflict (e.g., device already registered)
  • 410 Gone: Resource expired (e.g., single-use token used)
  • 429 Too Many Requests: Rate limit exceeded
  • 500 Internal Server Error: Server error

Common Error Messages

{
  "message": "Invalid biometric token",
  "statusCode": 401
}
{
  "message": "Device already registered for this user",
  "statusCode": 409
}
{
  "message": "Insufficient trust level",
  "statusCode": 403
}
{
  "message": "Action confirmation token already used",
  "statusCode": 410
}
{
  "message": "Rate limit exceeded",
  "statusCode": 429
}

Security Considerations

Token Types and Lifetimes

Token Type Purpose Lifetime Claims
Standard Access Web authentication 8 hours Standard user claims
Biometric Access Mobile authentication 15 minutes Enhanced with device info
Standard Refresh Token renewal 3-30 days Basic user info
Biometric Refresh Mobile token renewal 30 days Device binding + rotation
Action Confirmation Single-use confirmations 5 minutes Action-specific + nonce

Cryptographic Standards

Component Algorithm Key Size
JWT Signing HMAC-SHA256 256 bits
Device Signatures ES256 (recommended) 256 bits
Device Signatures RS256/PS256 2048+ bits
Challenge Generation CSPRNG 512 bits
Field Encryption AES-256-GCM 256 bits

Security Headers

All API responses include security headers:

  • Strict-Transport-Security
  • Content-Security-Policy
  • X-Content-Type-Options: nosniff
  • X-Frame-Options: DENY
  • X-XSS-Protection: 1; mode=block

Input Validation

  • All input is validated against strict patterns
  • File uploads limited to 10KB for public keys
  • Device names restricted to alphanumeric + limited special characters
  • Action payloads limited to 4KB JSON

Integration Examples

Mobile App Registration

// 1. Generate key pair
const { publicKey, keyAlgorithm } = await BiometricService.generateKeyPair();

// 2. Request challenge
const challengeResponse = await fetch('/api/v1/auth/devices/register/challenge', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${accessToken}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    deviceName: 'User iPhone 15',
    deviceType: 'mobile',
    deviceFingerprint: await getDeviceFingerprint(),
    publicKey: publicKey,
    keyAlgorithm: keyAlgorithm
  })
});

// 3. Sign and verify
const signature = await signWithBiometric(challengeResponse.challenge);
await fetch('/api/v1/auth/devices/register/verify', {
  method: 'POST',
  headers: { 'Authorization': `Bearer ${accessToken}` },
  body: JSON.stringify({
    sessionId: challengeResponse.sessionId,
    signedChallenge: signature
  })
});

Web Action Confirmation

// 1. Initiate confirmation
const confirmation = await fetch('/api/v1/auth/confirmation/initiate', {
  method: 'POST',
  headers: { 'Authorization': `Bearer ${accessToken}` },
  body: JSON.stringify({
    actionType: 'payment_approval',
    actionPayload: { amount: 50000, currency: 'VND' }
  })
});

// 2. Poll for status
const pollStatus = async (confirmationId) => {
  const response = await fetch(`/api/v1/auth/confirmation/${confirmationId}/status`);
  return response.data.status;
};

Service-to-Service Token Verification

// Verify token from another service
const response = await fetch('/internal/verify', {
  method: 'GET',
  headers: {
    'Authorization': `Bearer ${userToken}`,
    'X-Service-Name': 'document-service'
  }
});

if (response.ok) {
  const { valid, claims } = await response.json();
  // Use claims for authorization
}

This API reference provides comprehensive documentation for all authentication endpoints, including the new WebAuthn/passkey support and detailed examples for common integration patterns.