API Authentication & Security

Moose supports two authentication mechanisms for securing your API endpoints:

  • API Keys - Simple, static authentication for internal applications and getting started
  • JWT (JSON Web Tokens) - Token-based authentication for integration with existing identity providers

Choose the method that fits your use case, or use both together with custom configuration.

Do you want to use API Keys?

API keys are the simplest way to secure your Moose endpoints. They’re ideal for:

  • Internal applications and microservices
  • Getting started quickly with authentication
  • Scenarios where you control both client and server

How API Keys Work

API keys use PBKDF2 HMAC SHA256 hashing for secure storage. You generate a token pair (plain-text and hashed) using the Moose CLI, store the hashed version in environment variables, and send the plain-text version in your request headers.

Step 1: Generate API Keys

Generate tokens and hashed keys using the Moose CLI:

moose generate hash-token

Output:

  • ENV API Keys: Hashed key for environment variables (use this in your server configuration)
  • Bearer Token: Plain-text token for client applications (use this in Authorization headers)

MooseTip:

Use the hashed key for environment variables and moose.config.toml. Use the plain-text token in your Authorization: Bearer token headers.

Step 2: Configure API Keys with Environment Variables

Set environment variables with the hashed API keys you generated:

# For ingest endpoints
export MOOSE_INGEST_API_KEY='your_pbkdf2_hmac_sha256_hashed_key'
 
# For analytics endpoints  
export MOOSE_CONSUMPTION_API_KEY='your_pbkdf2_hmac_sha256_hashed_key'
 
# For admin endpoints
export MOOSE_ADMIN_TOKEN='your_plain_text_token'

Or set the admin API key in moose.config.toml:

moose.config.toml
[authentication]
admin_api_key = "your_pbkdf2_hmac_sha256_hashed_key"

Storing Admin API Keys in Project Configuration File

Storing the admin_api_key (which is a PBKDF2 HMAC SHA256 hash) in your moose.config.toml file is an acceptable practice, even if the file is version-controlled. This is because the actual plain-text Bearer token (the secret) is not stored. The hash is computationally expensive to reverse, ensuring that your secret is not exposed in the codebase.

Step 3: Make Authenticated Requests

All authenticated requests require the Authorization header with the plain-text token:

# Using curl
curl -H "Authorization: Bearer your_plain_text_token_here" \
     https://your-moose-instance.com/ingest/YourDataModel
 
# Using JavaScript
fetch('https://your-moose-instance.com/api/endpoint', {
  headers: {
    'Authorization': 'Bearer your_plain_text_token_here'
  }
})

Do you want to use JWTs?

JWT authentication integrates with existing identity providers and follows standard token-based authentication patterns. Use JWTs when:

  • You have an existing identity provider (Auth0, Okta, etc.)
  • You need user-specific authentication and authorization
  • You want standard OAuth 2.0 / OpenID Connect flows

How JWT Works

Moose validates JWT tokens using RS256 algorithm with your identity provider’s public key. You configure the expected issuer and audience, and Moose handles token verification automatically.

Step 1: Configure JWT Settings

Option A: Configure in moose.config.toml

[jwt]
# Your JWT public key (PEM-formatted RSA public key)
secret = """
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy...
-----END PUBLIC KEY-----
"""
# Expected JWT issuer
issuer = "https://my-auth-server.com/"
# Expected JWT audience  
audience = "my-moose-app"

MooseTip:

The secret field should contain your JWT public key used to verify signatures using RS256 algorithm.

Option B: Configure with Environment Variables

You can also set these values as environment variables:

.env
MOOSE_JWT_PUBLIC_KEY=your_jwt_public_key # PEM-formatted RSA public key (overrides `secret` in `moose.config.toml`)
MOOSE_JWT_ISSUER=your_jwt_issuer # Expected JWT issuer (overrides `issuer` in `moose.config.toml`)
MOOSE_JWT_AUDIENCE=your_jwt_audience # Expected JWT audience (overrides `audience` in `moose.config.toml`)

Step 2: Make Authenticated Requests

Send requests with the JWT token in the Authorization header:

# Using curl
curl -H "Authorization: Bearer your_jwt_token_here" \
     https://your-moose-instance.com/ingest/YourDataModel
 
# Using JavaScript
fetch('https://your-moose-instance.com/api/endpoint', {
  headers: {
    'Authorization': 'Bearer your_jwt_token_here'
  }
})

Want to use both? Here’s the caveats

You can configure both JWT and API Key authentication simultaneously. When both are configured, Moose’s authentication behavior depends on the enforce_on_all_* flags.

Understanding Authentication Priority

Default Behavior (No Enforcement)

By default, when both JWT and API Keys are configured, Moose tries JWT validation first, then falls back to API Key validation:

moose.config.toml
[jwt]
# JWT configuration
secret = "..."
issuer = "https://my-auth-server.com/"
audience = "my-moose-app"
# enforce flags default to false
.env
# API Key configuration
MOOSE_INGEST_API_KEY='your_pbkdf2_hmac_sha256_hashed_key'
MOOSE_CONSUMPTION_API_KEY='your_pbkdf2_hmac_sha256_hashed_key'

For Ingest Endpoints (/ingest/*):

  • Attempts JWT validation first (RS256 signature check)
  • Falls back to API Key validation (PBKDF2 HMAC SHA256) if JWT fails

For Analytics Endpoints (/api/*):

  • Same fallback behavior as ingest endpoints

This allows you to use either authentication method for your clients.

Enforcing JWT Only

If you want to only accept JWT tokens (no API key fallback), set the enforcement flags:

moose.config.toml
[jwt]
secret = "..."
issuer = "https://my-auth-server.com/"
audience = "my-moose-app"
# Only accept JWT, no API key fallback
enforce_on_all_ingest_apis = true
enforce_on_all_consumptions_apis = true

Result: When enforcement is enabled, API Key authentication is disabled even if the environment variables are set. Only valid JWT tokens will be accepted.

Common Use Cases

Use Case 1: Different Auth for Different Endpoints

Configure JWT for user-facing analytics endpoints, API keys for internal ingestion:

moose.config.toml
[jwt]
secret = "..."
issuer = "https://my-auth-server.com/"
audience = "my-moose-app"
enforce_on_all_consumptions_apis = true  # JWT only for /api/*
enforce_on_all_ingest_apis = false        # Allow fallback for /ingest/*
.env
MOOSE_INGEST_API_KEY='hashed_key_for_internal_services'

Use Case 2: Migration from API Keys to JWT

Start with both configured, no enforcement. Gradually migrate clients to JWT. Once complete, enable enforcement:

moose.config.toml
[jwt]
secret = "..."
issuer = "https://my-auth-server.com/"
audience = "my-moose-app"
# Start with both allowed during migration
enforce_on_all_ingest_apis = false
enforce_on_all_consumptions_apis = false
# Later, enable to complete migration
# enforce_on_all_ingest_apis = true
# enforce_on_all_consumptions_apis = true

Admin Endpoints

Admin endpoints use API key authentication exclusively (configured separately from ingest/analytics endpoints).

Configuration precedence (highest to lowest):

  1. --token CLI parameter (plain-text token)
  2. MOOSE_ADMIN_TOKEN environment variable (plain-text token)
  3. admin_api_key in moose.config.toml (hashed token)

Example:

# Option 1: CLI parameter
moose remote plan --token your_plain_text_token
 
# Option 2: Environment variable
export MOOSE_ADMIN_TOKEN='your_plain_text_token'
moose remote plan
 
# Option 3: Config file
# In moose.config.toml:
# [authentication]
# admin_api_key = "your_pbkdf2_hmac_sha256_hashed_key"

Security Best Practices

  • Never commit plain-text tokens to version control - Always use hashed keys in configuration files
  • Use environment variables for production - Keep secrets out of your codebase
  • Generate unique tokens for different environments - Separate development, staging, and production credentials
  • Rotate tokens regularly - Especially for long-running production deployments
  • Choose the right method for your use case:
    • Use API Keys for internal services and getting started
    • Use JWT when integrating with identity providers or need user-level auth
  • Store hashed keys safely - The PBKDF2 HMAC SHA256 hash in moose.config.toml is safe to version control, but the plain-text token should only exist in secure environment variables or secret management systems

Warning:

Never commit plain-text tokens to version control. Use hashed keys in configuration files and environment variables for production.