First API Call
This tutorial walks you through the complete flow of registering, logging in, and accessing protected resources.
Prerequisites
- CORTEX running locally (see Quick Start)
- A seeded database with at least one tenant
- cURL or an API client like Postman
Step 1: Check the API is Running
curl http://localhost:8091/health
Expected response:
{
"status": "ok",
"service": "cortex-core",
"version": "0.1.0"
}
Step 2: Get Available Tenants
If you have access to the database, query for tenant IDs:
SELECT id, name, slug FROM "Tenant" LIMIT 5;
Or use the seeded tenant ID from the database seed script.
Step 3: Register a New User
curl -X POST http://localhost:8091/auth/register \
-H "Content-Type: application/json" \
-d '{
"email": "john.doe@example.com",
"password": "SecureP@ss123",
"firstName": "John",
"lastName": "Doe",
"tenantId": "YOUR_TENANT_ID"
}'
Response (201 Created)
{
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "john.doe@example.com",
"firstName": "John",
"lastName": "Doe",
"tenantId": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"status": "ACTIVE",
"createdAt": "2024-01-15T10:30:00.000Z"
}
}
Copy the accessToken value — you'll need it for subsequent requests.
Step 4: Login (If Already Registered)
curl -X POST http://localhost:8091/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "john.doe@example.com",
"password": "SecureP@ss123"
}'
Step 5: Access a Protected Endpoint
Use the access token in the Authorization header:
curl http://localhost:8091/auth/me \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
Response
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "john.doe@example.com",
"firstName": "John",
"lastName": "Doe",
"tenantId": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"status": "ACTIVE"
}
Step 6: List Users in Your Tenant
curl http://localhost:8091/users \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
Response
{
"data": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "john.doe@example.com",
"firstName": "John",
"lastName": "Doe",
"status": "ACTIVE"
}
],
"pagination": {
"total": 1,
"page": 1,
"limit": 20,
"totalPages": 1
}
}
Step 7: Refresh Your Token
When the access token expires (after 15 minutes), use the refresh token:
curl -X POST http://localhost:8091/auth/refresh \
-H "Content-Type: application/json" \
-d '{
"refreshToken": "YOUR_REFRESH_TOKEN"
}'
Response
{
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
Note that both tokens are new. The old refresh token is now invalid. This is a security feature called token rotation.
Step 8: Logout
curl -X POST http://localhost:8091/auth/logout \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
After logout, the refresh token is invalidated and cannot be used to obtain new tokens.
Common Errors
401 Unauthorized
{
"type": "https://api.cortex.purplelab.ai/errors/unauthorized",
"title": "Unauthorized",
"status": 401,
"detail": "Invalid or expired access token"
}
Solution: Login again or use the refresh token endpoint.
400 Bad Request
{
"type": "https://api.cortex.purplelab.ai/errors/validation",
"title": "Validation Error",
"status": 400,
"detail": "email must be a valid email address"
}
Solution: Check your request body matches the expected format.
Next Steps
- Authentication Overview — Learn about the full auth system
- API Reference — Explore all endpoints interactively