Authentication
How to authenticate with the Subscriptions Service API using JWT tokens and internal API keys.
Overview
The Subscriptions Service uses a two-tier auth model:
- JWT Bearer tokens for all user-facing endpoints (subscriptions, plans, trials, invoices, etc.)
- Internal API key for jobs/scheduler endpoints (via
x-internal-api-keyheader)
The tenantId is extracted from the JWT claims automatically via the @CurrentTenant() decorator. You never need to pass it as a URL parameter.
Obtaining a JWT Token
Login via auth-svcbash
curl -X POST https://535ubezkse.execute-api.us-east-1.amazonaws.com/auth/v1/login/email \
-H "Content-Type: application/json" \
-H "x-tenant-id: 00000000-0000-0000-0000-000000000001" \
-d '{
"email": "organizer@eventzr.com",
"password": "Password123!"
}'
# Response:
# {
# "data": {
# "accessToken": "eyJhbGciOiJIUzI1NiIs...",
# "refreshToken": "eyJhbGciOiJIUzI1NiIs...",
# "expiresIn": 3600
# }
# }Use the token with subscriptions-svcbash
export TOKEN="<access-token-from-response>"
curl -X GET https://535ubezkse.execute-api.us-east-1.amazonaws.com/subscriptions/v1/subscriptions \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json"Refresh an expired tokenbash
curl -X POST https://535ubezkse.execute-api.us-east-1.amazonaws.com/auth/v1/refresh \
-H "Content-Type: application/json" \
-d '{ "refreshToken": "eyJhbGciOiJSUzI1NiIs..." }'Test Credentials
Staging Environment Credentials
Use these credentials to test the API in the Scalar playground above.
| Role | Password | Tenant ID | |
|---|---|---|---|
| Organizer | organizer@eventzr.com | Password123! | 00000000-0000-0000-0000-000000000001 |
| User | user@eventzr.com | Password123! | 00000000-0000-0000-0000-000000000001 |
| Developer (MFA required) | dev@eventzr.com | Password123! | 00000000-0000-0000-0000-000000000001 |
Internal API Key (Jobs Endpoints)
Fail-Closed Security
Jobs endpoints use an internal API key instead of JWT. The guard is fail-closed: if INTERNAL_API_KEY is not configured, all requests are rejected with 401.
Call a jobs endpointbash
# Jobs endpoints bypass JWT — use x-internal-api-key header instead
curl -X POST https://535ubezkse.execute-api.us-east-1.amazonaws.com/subscriptions/v1/jobs/process-renewals \
-H "x-internal-api-key: <INTERNAL_API_KEY>" \
-H "Content-Type: application/json"JWT Claims Structure
Decoded JWT payloadjson
{
"sub": "user-uuid",
"tenantId": "tenant-uuid",
"email": "user@example.com",
"roles": ["user", "organizer", "admin"],
"planTier": "professional",
"iat": 1740000000,
"exp": 1740003600
}Standard Headers
| Header | Required | Description |
|---|---|---|
Authorization | Yes (user endpoints) | Bearer JWT token |
x-internal-api-key | Yes (jobs endpoints) | Internal API key for scheduler/cron endpoints |
Content-Type | POST/PUT/PATCH | application/json |
x-request-id | No | Request trace ID (UUID), auto-generated if absent |
x-tenant-id | Recommended | Tenant UUID for explicit tenant filtering |
Idempotency-Key | No | Idempotency key for write operations (24h TTL) |
Role-Based Access Control
Endpoints are protected by @Roles() decorator. Common roles:
| Role | Access |
|---|---|
user | View own subscriptions, plans, trials, invoices |
organizer | Create/manage subscriptions, upgrade/downgrade, view analytics |
admin | Full access including plan management, bulk operations, discount codes |
Response Envelope
Standard response formatjson
{
"data": { ... },
"error": null,
"page": {
"next_cursor": "eyJwYWdlIjoyLCJsaW1pdCI6MjB9",
"has_more": true,
"limit": 20
},
"meta": {
"request_id": "550e8400-e29b-41d4-a716-446655440000",
"trace_id": "abc123",
"tenant_id": "tenant-uuid"
}
}