Skip to main content

Overview

Chronoverse uses a hybrid authentication approach combining:
  • JWT tokens (short-lived, 15 minutes) for authorization
  • Session cookies (long-lived) for maintaining user sessions
  • CSRF tokens for protecting state-changing operations
All authenticated endpoints require both a valid session cookie and CSRF token for state-changing operations (POST, PUT, PATCH, DELETE).

JWT Token Details

JSON Web Tokens (JWT) are used for secure authorization between services.

Token Structure

Tokens are signed using the EdDSA algorithm with Ed25519 keys and contain the following claims:
aud
string
required
Audience - The service name (chronoverse)
iss
string
required
Issuer - The service that issued the token
sub
string
required
Subject - The user ID
role
string
required
User role - Either user or admin
iat
integer
required
Issued at - Unix timestamp when token was created
nbf
integer
required
Not before - Unix timestamp when token becomes valid
exp
integer
required
Expiration - Unix timestamp when token expires (15 minutes from issuance)

Token Expiry

JWT tokens expire after 15 minutes for security. However, the session remains valid longer, and tokens are automatically reissued on subsequent requests.
Tokens are short-lived by design. The server automatically handles token renewal as long as your session is valid.

Authentication Flow

1. Register a New User

Create a new user account:
curl -X POST http://localhost:8080/auth/register \
  -H "Content-Type: application/json" \
  -d '{
    "email": "user@example.com",
    "password": "your-secure-password"
  }'
Request Body:
email
string
required
User’s email address
password
string
required
User’s password
Response:
  • Status: 201 Created
  • Sets two HTTP-only cookies:
    • session - Encrypted session token
    • csrf - CSRF protection token

2. Login

Authenticate an existing user:
curl -X POST http://localhost:8080/auth/login \
  -H "Content-Type: application/json" \
  -c cookies.txt \
  -d '{
    "email": "user@example.com",
    "password": "your-secure-password"
  }'
Request Body:
email
string
required
User’s email address
password
string
required
User’s password
Response:
  • Status: 201 Created
  • Sets two HTTP-only cookies:
    • session - Encrypted session token containing the JWT
    • csrf - CSRF protection token
Save the cookies using -c cookies.txt to use them in subsequent requests.

3. Using Authenticated Endpoints

For GET requests (read-only operations):
curl -X GET http://localhost:8080/users \
  -b cookies.txt
For state-changing operations (POST, PUT, PATCH, DELETE):
curl -X POST http://localhost:8080/workflows \
  -b cookies.txt \
  -H "Content-Type: application/json" \
  -d '{
    "name": "My Workflow",
    "payload": "...",
    "kind": "CONTAINER",
    "interval": 3600
  }'
Both the session and csrf cookies must be included for state-changing operations. Read-only operations only require the session cookie.

4. Validate Session

Check if your current session is valid:
curl -X POST http://localhost:8080/auth/validate \
  -b cookies.txt
Response:
  • Status: 200 OK - Session is valid
  • Status: 401 Unauthorized - Session is invalid or expired

5. Logout

End your session and clear cookies:
curl -X POST http://localhost:8080/auth/logout \
  -b cookies.txt
Response:
  • Status: 204 No Content
  • Clears both session and csrf cookies
  • Deletes the session from the server
The session cookie contains an encrypted JWT token:
  • Name: session
  • HttpOnly: true (not accessible via JavaScript)
  • Secure: Depends on deployment (true for HTTPS)
  • SameSite: Configurable (LAX, STRICT, or NONE)
  • Path: /
  • Expiry: Configured session expiry duration
The csrf cookie provides CSRF protection:
  • Name: csrf
  • HttpOnly: true
  • Secure: Depends on deployment
  • SameSite: Configurable
  • Path: /
  • Expiry: Configured CSRF expiry duration
The CSRF token is automatically validated by the server for all state-changing operations.

Security Best Practices

Always use HTTPS in production to protect session cookies and tokens from interception.
JWT tokens are automatically reissued on each request, so you don’t need to manually handle token refresh as long as your session is valid.
Sessions expire after a configured duration of inactivity. Implement proper logout functionality in your application.
All state-changing operations require a valid CSRF token, protecting against cross-site request forgery attacks.

Error Responses

Authentication Errors

401 Unauthorized
  • session not found - No session cookie provided
  • invalid token - JWT token is invalid or malformed
  • failed to decrypt session - Session cookie is corrupted
  • invalid auth token - Session not found in Redis store
400 Bad Request
  • csrf token not found - CSRF token missing for state-changing operations
  • invalid request body - Request body is malformed
412 Precondition Failed
  • failed to verify csrf token - CSRF token validation failed

Example Error Response

# Missing session cookie
curl -X GET http://localhost:8080/users
# Response: 401 Unauthorized
# Body: session not found

# Missing CSRF token for state-changing operation
curl -X POST http://localhost:8080/workflows \
  -b "session=invalid-session" \
  -H "Content-Type: application/json" \
  -d '{...}'
# Response: 400 Bad Request
# Body: csrf token not found

Programmatic Usage

JavaScript/TypeScript Example

// Login and store cookies
const response = await fetch('http://localhost:8080/auth/login', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  credentials: 'include', // Important: include cookies
  body: JSON.stringify({
    email: 'user@example.com',
    password: 'your-password',
  }),
});

if (response.status === 201) {
  console.log('Login successful');
  // Cookies are automatically stored by the browser
}

// Make authenticated request
const userResponse = await fetch('http://localhost:8080/users', {
  method: 'GET',
  credentials: 'include', // Include cookies
});

const userData = await userResponse.json();

Python Example

import requests

# Create a session to persist cookies
session = requests.Session()

# Login
response = session.post(
    'http://localhost:8080/auth/login',
    json={
        'email': 'user@example.com',
        'password': 'your-password'
    }
)

if response.status_code == 201:
    print('Login successful')
    # Cookies are automatically stored in the session

# Make authenticated request
user_response = session.get('http://localhost:8080/users')
user_data = user_response.json()

# Logout
session.post('http://localhost:8080/auth/logout')

Internal Service Authentication

For internal service-to-service communication, the API supports admin role tokens:
  • Tokens with role: admin bypass certain authorization checks
  • Admin role is identified by checking the role claim in the JWT token
  • Use IsInternalService(ctx) to verify admin role from metadata
Admin role tokens should only be used for internal service communication and never exposed to end users.

Build docs developers (and LLMs) love