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-tokenOutput:
- 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
Authorizationheaders)
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:
[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:
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:
[jwt]
# JWT configuration
secret = "..."
issuer = "https://my-auth-server.com/"
audience = "my-moose-app"
# enforce flags default to false# 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:
[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 = trueResult: 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:
[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/*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:
[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 = trueAdmin Endpoints
Admin endpoints use API key authentication exclusively (configured separately from ingest/analytics endpoints).
Configuration precedence (highest to lowest):
--tokenCLI parameter (plain-text token)MOOSE_ADMIN_TOKENenvironment variable (plain-text token)admin_api_keyinmoose.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.tomlis 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.