This guide covers authentication and authorization patterns in the PERS API.
PERS uses a tiered security architecture designed for flexibility and security:
- Tenant Context (
X-Project-Key): Identifies the project/tenant. Required for almost all requests (Public & Authenticated). - 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.
- Token Binding (DPoP): Binds access tokens to a client-held private key (Optional but Highly Recommended).
Note: We have deprecated legacy
x-api-keyusage for business logic authentication in favor of strict JWT-based flows.X-Project-Keyis solely for tenant context resolution.
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...Authenticated operations require a valid JSON Web Token (JWT) in the Authorization header.
- Header:
Authorization: Bearer <token> - Format: Standard JWT (JSON Web Token).
Obtain PERS-native JWTs by exchanging external credentials at the unified auth endpoint.
Endpoint: POST /auth/token
| Field | Type | Required | Description |
|---|---|---|---|
authToken | string | Yes | The proof from the external provider (e.g., Firebase ID Token, DFNS Auth Token, etc.). |
authType | string | No | The type of principal. Defaults to 'user'. Values: 'user', 'tenant' (admin), 'business'. |
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": { ... }
}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.
- Client generates a temporary key pair (e.g., ES256).
- Client creates a DPoP proof (a JWT signed with the private key) containing the HTTP method and URI.
- Client sends the
dpopheader with the proof. - Server binds the issued access token to the public key in the DPoP proof.
- Subsequent Requests: Client must send a new DPoP proof with each request using the bonded token.
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
POST /auth/token
X-Project-Key: ...
dpop: <dpop-proof-jwt>
...The server will embed the DPoP key thumbprint into the returned accessToken.
| Auth Type | Headers Required | Use Case |
|---|---|---|
| Public | X-Project-Key | Viewing public campaigns, checking user existence, public catalogs. |
| User | X-Project-KeyAuthorization: Bearer <user_jwt> | User-specific operations, claim rewards, view simplified profile. |
| Business | X-Project-KeyAuthorization: Bearer <biz_jwt> | Managing business assets, campaigns (if delegated). |
| Admin | Authorization: Bearer <admin_jwt>(Tenant context often embedded) | Full tenant administration, configuration. |
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.
Many PERS endpoints support multiple authentication methods, providing flexibility for different integration scenarios.
The /files/entity-storage-url endpoint accepts multiple authentication types:
// 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'
})
});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': '...',
},
...
});The official TypeScript library providing type-safe contracts, DTOs, and error handling for PERS API integration.
npm install @explorins/pers-sharedThe 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;PERS implements a counterfactual wallet system that provides users with blockchain addresses before their first transaction.
Counterfactual Wallets & Signing Accounts Guide →
PERS API uses a centralized error handling system via the ErrorFactory pattern.
| Category | HTTP Status | Description | Retryable |
|---|---|---|---|
SECURITY | 401 | Authentication missing or expired | No |
SECURITY | 403 | Permissions insufficient | No |
VALIDATION | 400 | Invalid payload | No |
RATE_LIMIT | 429 | Too many requests | Yes |
{
"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.
- DPoP: Use DPoP to bind tokens to your client instance.
- Storage: Store JWT tokens securely.
- HTTPS: Always use HTTPS.
- Context Only: Remember
X-Project-Keyis for context, not user identity. - Rotation: Rotate keys if they are exposed in unauthorized contexts.
- Obtain Project Key: Use your tenant's
X-Project-Key. - Authenticate: Use
POST /auth/tokento exchange your provider's token for a PERS JWT. - Secure: Add
dpopheaders for maximum security. - Call API: Use the JWT in the
Authorizationheader for protected endpoints.