Skip to content
Last updated

This guide covers authentication and authorization patterns in the PERS API.


Architecture Overview

PERS uses a tiered security architecture designed for flexibility and security:

  1. Tenant Context (X-Project-Key): Identifies the project/tenant. Required for almost all requests (Public & Authenticated).
  2. Authentication (JWT): Identifies the principal (User, Business, or Admin).
    • Users: Authenticated via JWTs obtained through Token Exchange.
    • Businesses: Authenticated via JWTs.
    • Admins: Authenticated via Tenant-scoped JWTs.
  3. Token Binding (DPoP): Binds access tokens to a client-held private key (Optional but Highly Recommended).

Note: We have deprecated legacy x-api-key usage for business logic authentication in favor of strict JWT-based flows. X-Project-Key is solely for tenant context resolution.


1. Project Identification (Public Access)

All API requests must identify the target tenant/project context using the Project Key.

  • Header: X-Project-Key
  • Purpose: Resolves the tenant configuration, feature flags, and ensures data isolation.
  • Scope: By itself, grants access to Public endpoints (e.g., browsing catalogs, basic availability checks).
  • Format: 64-character hex string. For testnet campaigns, prefix with pk_test_.
GET /campaigns
X-Project-Key: a1b2c3d4e5f6789...

2. Authentication (JWT)

Authenticated operations require a valid JSON Web Token (JWT) in the Authorization header.

  • Header: Authorization: Bearer <token>
  • Format: Standard JWT (JSON Web Token).

Unified Token Endpoint

Obtain PERS-native JWTs by exchanging external credentials at the unified auth endpoint.

Endpoint: POST /auth/token

Request Body (SessionAuthRequestDTO)

FieldTypeRequiredDescription
authTokenstringYesThe proof from the external provider (e.g., Firebase ID Token, DFNS Auth Token, etc.).
authTypestringNoThe type of principal. Defaults to 'user'. Values: 'user', 'tenant' (admin), 'business'.

Example: User Login (Token Exchange)

POST /auth/token
Host: api.pers.ninja
X-Project-Key: a1b2c3d4e5f6789...
Content-Type: application/json

{
  "authToken": "external_provider_jwt_token",
  "authType": "user"
}

Response:

{
  "accessToken": "pers_access_jwt...",
  "refreshToken": "pers_refresh_jwt...",
  "user": { ... }
}

3. DPoP (Demonstrating Proof-of-Possession)

Status: Optional but Highly Recommended for enhanced security.

DPoP binds an access token to a private key held by the client, preventing token replay attacks if the token is leaked. The PERS API supports DPoP validation on authentication and protected resource requests.

How Verification Works

  1. Client generates a temporary key pair (e.g., ES256).
  2. Client creates a DPoP proof (a JWT signed with the private key) containing the HTTP method and URI.
  3. Client sends the dpop header with the proof.
  4. Server binds the issued access token to the public key in the DPoP proof.
  5. Subsequent Requests: Client must send a new DPoP proof with each request using the bonded token.

Implementation Guide

Step 1: Generate DPoP Proof

Use a library or generate a standard DPoP JWT header:

  • Typ: dpop+jwt
  • Alg: ES256 (recommended)
  • Jwk: Public key

Claims:

  • htm: HTTP Method (e.g., POST)
  • htu: HTTP URI (e.g., https://api.pers.ninja/v2/auth/token)
  • iat: Issued At (timestamp)
  • jti: Unique ID

Step 2: Include Header

POST /auth/token
X-Project-Key: ...
dpop: <dpop-proof-jwt>
...

The server will embed the DPoP key thumbprint into the returned accessToken.


Authentication Methods Summary

Auth TypeHeaders RequiredUse Case
PublicX-Project-KeyViewing public campaigns, checking user existence, public catalogs.
UserX-Project-Key
Authorization: Bearer <user_jwt>
User-specific operations, claim rewards, view simplified profile.
BusinessX-Project-Key
Authorization: Bearer <biz_jwt>
Managing business assets, campaigns (if delegated).
AdminAuthorization: Bearer <admin_jwt>
(Tenant context often embedded)
Full tenant administration, configuration.

Note on Legacy API Keys

Older integrations may have used x-api-key for authentication. This pattern is deprecated. Please migrate to the JWT pattern using the /auth/token exchange flow for all secure operations.


Mixed Authentication Endpoints

Many PERS endpoints support multiple authentication methods, providing flexibility for different integration scenarios.

Example: File Upload Endpoint

The /files/entity-storage-url endpoint accepts multiple authentication types:

Business Integration

// JWT authentication for business file uploads
const response = await fetch('https://api.pers.ninja/v2/files/entity-storage-url', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer <business_jwt_token>',
    'X-Project-Key': 'a1b2c3d4e5f6789...',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    entityType: 'CAMPAIGN',
    operation: 'upload'
  })
});

User Integration

Authenticate first, then use the access token.

// 1. Exchange Token
const authResponse = await fetch('/auth/token', { ... }); 
// 2. Use Access Token
const response = await fetch('/files/entity-storage-url', {
  headers: {
    'Authorization': `Bearer ${accessToken}`,
    'X-Project-Key': '...',
  },
  ...
});

Client Libraries & SDKs

@explorins/pers-shared

The official TypeScript library providing type-safe contracts, DTOs, and error handling for PERS API integration.

Installation

npm install @explorins/pers-shared

Usage with New Auth Patterns

The library includes DTOs for the unified authentication flow:

import { 
  SessionAuthRequestDTO, 
  SessionAuthResponseDTO,
  AccountOwnerType 
} from '@explorins/pers-shared';

// 1. Prepare Authentication Request
const loginRequest: SessionAuthRequestDTO = {
  authToken: "firebase_id_token_or_other_proof",
  authType: AccountOwnerType.USER // or BUSINESS / TENANT
};

// 2. Call Unified Endpoint
// (Implementation depends on your HTTP client)
const response = await httpClient.post<SessionAuthResponseDTO>(
  '/auth/token', 
  loginRequest,
  {
    headers: { 'X-Project-Key': 'a1b2c3d4e5f6789...' }
  }
);

// 3. Use Tokens
const { accessToken, refreshToken, user } = response.data;

Counterfactual Wallets & User Signing

PERS implements a counterfactual wallet system that provides users with blockchain addresses before their first transaction.

Counterfactual Wallets & Signing Accounts Guide →


Error Handling

PERS API uses a centralized error handling system via the ErrorFactory pattern.

Error Response Categories

CategoryHTTP StatusDescriptionRetryable
SECURITY401Authentication missing or expiredNo
SECURITY403Permissions insufficientNo
VALIDATION400Invalid payloadNo
RATE_LIMIT429Too many requestsYes

Example: Authentication Required (401)

{
  "status": 401,
  "code": "AUTHENTICATION_REQUIRED",
  "category": "SECURITY",
  "message": "Please provide valid authentication credentials",
  "correlationId": "req-123..."
}

For a complete list of error codes, refer to the Error Handling Guide.


Security Best Practices

JWT Token Security

  • DPoP: Use DPoP to bind tokens to your client instance.
  • Storage: Store JWT tokens securely.
  • HTTPS: Always use HTTPS.

Project Key Security

  • Context Only: Remember X-Project-Key is for context, not user identity.
  • Rotation: Rotate keys if they are exposed in unauthorized contexts.

Getting Started

  1. Obtain Project Key: Use your tenant's X-Project-Key.
  2. Authenticate: Use POST /auth/token to exchange your provider's token for a PERS JWT.
  3. Secure: Add dpop headers for maximum security.
  4. Call API: Use the JWT in the Authorization header for protected endpoints.