Authentication
Authentication
NovaBilling uses a dual authentication model to provide secure, fine-grained access control for your billing operations.
Authentication Overview
| Method | Purpose | Scope |
|---|---|---|
| JWT Tokens | Tenant management | Register, login, manage API keys, update tenant settings |
| API Keys | Data operations | Customers, plans, subscriptions, invoices, payments, analytics |
This separation ensures that compromising an API key does not grant access to tenant management functions, and vice versa.
JWT Authentication
JWT (JSON Web Token) authentication is used for all tenant management operations. You obtain tokens by logging in with your tenant credentials.
Login
curl -X POST http://localhost:3000/api/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "admin@acmecorp.com",
"password": "securepassword123"
}'
import { NovaBillingClient } from 'novabilling';
const client = new NovaBillingClient({
baseUrl: 'http://localhost:3000'
});
const session = await client.auth.login({
email: 'admin@acmecorp.com',
password: 'securepassword123'
});
console.log('Access Token:', session.accessToken);
from novabilling import NovaBilling
client = NovaBilling(base_url="http://localhost:3000")
session = client.auth.login(
email="admin@acmecorp.com",
password="securepassword123"
)
print(f"Access Token: {session.access_token}")
The response contains an access token and a refresh token:
{
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
Using JWT Tokens
Include the access token in the Authorization header for all tenant management requests:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Token Refresh
Access tokens expire after 1 hour (3600 seconds). Use the refresh token to obtain a new access token without re-authenticating.
curl -X POST http://localhost:3000/api/auth/refresh \
-H "Content-Type: application/json" \
-d '{
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}'
const newSession = await client.auth.refresh({
refreshToken: session.refreshToken
});
console.log('New access token:', newSession.accessToken);
new_session = client.auth.refresh(
refresh_token=session.refresh_token
)
print(f"New access token: {new_session.access_token}")
Response:
{
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
Token Expiration Summary
| Token Type | Lifetime | Renewable |
|---|---|---|
| Access Token | 1 hour | Yes, via refresh token |
| Refresh Token | 30 days | Yes, each refresh issues a new one |
API Key Authentication
API keys are used for all data operations and provide a simpler authentication flow suited for server-to-server communication.
Creating API Keys
API keys are created using JWT authentication. You must be logged in as a tenant admin to create keys.
curl -X POST http://localhost:3000/api/tenants/me/api-keys \
-H "Content-Type: application/json" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
-d '{
"name": "Production Key",
"scopes": ["customers:read", "customers:write", "plans:read", "plans:write",
"subscriptions:read", "subscriptions:write", "invoices:read", "payments:read"]
}'
const apiKey = await client.apiKeys.create({
name: 'Production Key',
scopes: ['customers:read', 'customers:write', 'plans:read', 'plans:write',
'subscriptions:read', 'subscriptions:write', 'invoices:read', 'payments:read']
});
console.log('API Key:', apiKey.key);
console.log('Key ID:', apiKey.id);
api_key = client.api_keys.create(
name="Production Key",
scopes=["customers:read", "customers:write", "plans:read", "plans:write",
"subscriptions:read", "subscriptions:write", "invoices:read", "payments:read"]
)
print(f"API Key: {api_key.key}")
print(f"Key ID: {api_key.id}")
API Key Scopes
| Scope | Description |
|---|---|
customers:read | Read customer data |
customers:write | Create and update customers |
plans:read | Read plan data |
plans:write | Create and update plans |
subscriptions:read | Read subscription data |
subscriptions:write | Create and update subscriptions |
invoices:read | Read invoice data |
invoices:write | Create and update invoices |
payments:read | Read payment data |
payments:write | Process and refund payments |
analytics:read | Access analytics endpoints |
You can combine scopes based on your needs. For example, a reporting service might only need read scopes.
Using API Keys
Include the API key in the Authorization header for all data operation requests:
Authorization: Bearer sk_live_a1b2c3d4e5f6g7h8i9j0...
Listing API Keys
curl -X GET http://localhost:3000/api/tenants/me/api-keys \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."
const keys = await client.apiKeys.list();
for (const key of keys) {
console.log(`${key.name} (${key.id}) - Created: ${key.createdAt}`);
}
keys = client.api_keys.list()
for key in keys:
print(f"{key.name} ({key.id}) - Created: {key.created_at}")
Revoking API Keys
When an API key is compromised or no longer needed, revoke it immediately.
curl -X DELETE http://localhost:3000/api/tenants/me/api-keys/key_m9n8o7p6q5r4 \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."
await client.apiKeys.revoke('key_m9n8o7p6q5r4');
console.log('API key revoked successfully');
client.api_keys.revoke("key_m9n8o7p6q5r4")
print("API key revoked successfully")
Security Best Practices
- Use environment variables -- Never hardcode API keys in your source code. Store them in environment variables or a secrets manager.
export NOVABILLING_API_KEY="sk_live_a1b2c3d4e5f6g7h8i9j0..." - Use least-privilege scopes -- Only grant the scopes each API key actually needs. A key used for reading analytics does not need write scopes.
- Rotate keys regularly -- Create new API keys and revoke old ones on a regular schedule (e.g., every 90 days).
- Use separate keys per environment -- Create distinct API keys for development, staging, and production environments.
- Monitor key usage -- Review your API key usage in the tenant dashboard to detect any unusual activity.
- Never expose keys client-side -- API keys should only be used in server-side code. Never include them in frontend JavaScript, mobile apps, or any client-side code.
Error Responses
401 Unauthorized
Returned when no authentication credentials are provided or the credentials are invalid.
{
"statusCode": 401,
"message": "Invalid or missing authentication credentials"
}
403 Forbidden
Returned when the provided credentials are valid but lack the required permissions.
{
"statusCode": 403,
"message": "Insufficient permissions. Required: customers:write"
}
429 Too Many Requests
Returned when the rate limit is exceeded (100 requests per minute per tenant).
{
"statusCode": 429,
"message": "Rate limit exceeded. Try again in 30 seconds",
"retryAfter": 30
}