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 confirmationapproved: User confirmed with biometric signaturerejected: User explicitly rejectedexpired: 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-serviceResponse
{
"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-SecurityContent-Security-PolicyX-Content-Type-Options: nosniffX-Frame-Options: DENYX-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.