Skip to content

Authentication Guide

Satori uses JWT (JSON Web Tokens) for secure API authentication. This guide covers how to create, manage, and use authentication tokens.

Overview

Authentication in Satori follows this flow:

  1. Get your API token from your Satori administrator
  2. Use token in the Authorization header for all API requests
  3. Token validation happens automatically on each request

Getting Your API Token

Your API token is provided by your Satori administrator. If you need additional tokens, you can create them using your existing token.

Creating Additional Tokens

If you already have a token, you can create additional tokens:

curl -X POST "https://api.satorivault.com/api/tenants/{tenant_id}/tokens/" \
  -H "Authorization: Bearer <EXISTING_JWT_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Secondary Token",
    "expires_at": "2025-06-30T00:00:00Z"
  }'

Response:

{
  "id": "650e8400-e29b-41d4-a716-446655440000",
  "name": "Secondary Token",
  "key": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "is_active": true,
  "expires_at": "2025-06-30T00:00:00Z",
  "created_at": "2025-01-15T10:00:00Z"
}

Important: The key field contains your JWT token. Save it immediately - you cannot retrieve it again later.

Using Tokens

Authorization Header

Include the token in every API request:

curl -X GET "https://api.satorivault.com/api/tenants/{tenant_id}/" \
  -H "Authorization: Bearer <YOUR_JWT_TOKEN>"

Note: Replace {tenant_id} with your tenant ID and https://api.satorivault.com with your actual API URL.

Python Example

import requests

JWT_TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."

headers = {
    "Authorization": f"Bearer {JWT_TOKEN}",
    "Content-Type": "application/json"
}

response = requests.get(
    "{api_host}/api/tenants/{tenant_id}/",
    headers=headers
)

JavaScript/TypeScript Example

const JWT_TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...";

const response = await fetch("{api_host}/api/tenants/{tenant_id}/", {
  headers: {
    Authorization: `Bearer ${JWT_TOKEN}`,
    "Content-Type": "application/json",
  },
});

Token Management

Listing Tokens

List all tokens for your tenant:

curl -X GET "https://api.satorivault.com/api/tenants/{tenant_id}/tokens/" \
  -H "Authorization: Bearer <YOUR_JWT_TOKEN>"

Response:

[
  {
    "id": "650e8400-e29b-41d4-a716-446655440000",
    "name": "Production API Token",
    "is_active": true,
    "expires_at": "2025-12-31T23:59:59Z",
    "last_used": "2025-01-15T14:30:00Z",
    "created_at": "2025-01-15T10:00:00Z"
  }
]

Note: The actual token key is not returned for security reasons.

Deactivating Tokens

Deactivate a token (instead of deleting):

curl -X PUT "https://api.satorivault.com/api/tenants/{tenant_id}/tokens/{token_id}" \
  -H "Authorization: Bearer <YOUR_JWT_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
    "is_active": false
  }'

Token Expiration

Tokens can have optional expiration dates:

{
  "name": "Temporary Token",
  "expires_at": "2025-06-30T00:00:00Z"
}
  • If expires_at is not provided, the token never expires
  • Expired tokens cannot be used for authentication
  • Check token expiration before making requests

Security Best Practices

✅ DO:

  • Store tokens securely: Use environment variables or secret management
  • Use different tokens: Separate tokens for different applications or environments
  • Set expiration dates: Especially for temporary or test tokens
  • Rotate tokens regularly: Create new tokens and deactivate old ones
  • Use descriptive names: Make it easy to identify token purpose
  • Monitor token usage: Check last_used to identify unused tokens

❌ DON'T:

  • Commit tokens to version control: Never commit .env files with tokens
  • Share tokens between team members: Each person should have their own token
  • Reuse tokens across applications: Use separate tokens for different apps
  • Ignore expiration dates: Check and renew tokens before they expire

Environment Variables

# .env file (never commit this!)
SATORI_JWT_TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
SATORI_MASTER_KEY=your-master-key-here
SATORI_BASE_URL={api_host}
import os
from dotenv import load_dotenv

load_dotenv()

JWT_TOKEN = os.getenv("SATORI_JWT_TOKEN")
MASTER_KEY = os.getenv("SATORI_MASTER_KEY")
BASE_URL = os.getenv("SATORI_BASE_URL", "{api_host}")

Error Handling

401 Unauthorized

Token is missing, invalid, or expired:

if response.status_code == 401:
    # Token is invalid or expired
    # Create a new token or check expiration
    raise AuthenticationError("Invalid or expired token")

403 Forbidden

Token is valid but doesn't have access to the requested resource:

if response.status_code == 403:
    # Token doesn't have access to this enclave
    raise PermissionError("Access denied")

Token Scoping

Tokens are scoped to your tenant:

  • All operations using a token are limited to your tenant's data
  • Enclaves within your tenant are accessible with your token
  • You can create multiple tokens for different purposes (e.g., different applications or environments)

Token Management

Your tokens are managed through the tenant API endpoints. You can:

  • Create new tokens for different applications or environments
  • List all your tokens
  • Deactivate tokens that are no longer needed
  • Set expiration dates for temporary tokens

All token management operations require authentication with an existing token.

Token Refresh Strategy

While Satori doesn't provide automatic token refresh, you can implement your own:

class TokenManager:
    def __init__(self, base_url, tenant_id, existing_token):
        self.base_url = base_url
        self.tenant_id = tenant_id
        self.existing_token = existing_token
        self.token = None
        self.token_expires = None

    def get_token(self):
        if self.token and self.is_token_valid():
            return self.token

        # Create new token using existing token
        response = requests.post(
            f"{self.base_url}/api/tenants/{self.tenant_id}/tokens/",
            headers={"Authorization": f"Bearer {self.existing_token}"},
            json={"name": "Auto-refreshed token"}
        )
        token_data = response.json()
        self.token = token_data["key"]
        self.token_expires = token_data.get("expires_at")
        return self.token

    def is_token_valid(self):
        if not self.token_expires:
            return True  # Never expires
        return datetime.now() < datetime.fromisoformat(self.token_expires)

Next Steps