Authentication
All API requests to the MLM Platform require authentication using a tenant API key.
API keys are passed in the x-tenant-api-key HTTP header:
x-tenant-api-key: mlm_live_abc123...
Key Types
| Prefix | Environment | Usage |
|---|
mlm_live_ | LIVE | Production data |
mlm_sandbox_ | SANDBOX | Testing and development |
Never use LIVE keys in development or testing environments.
Creating API Keys
- Navigate to Settings > API Keys in the Admin Dashboard
- Click Create API Key
- Select the environment (LIVE or SANDBOX)
- Add an optional description
- Click Create
API keys are shown only once at creation. Store them securely.
Security Best Practices
Never Expose Keys Client-Side
API keys should only be used in server-side code:
// BAD - Never do this in browser code
const response = await fetch('/api/users', {
headers: {
'x-tenant-api-key': 'mlm_live_abc123' // Exposed to users!
}
});
// GOOD - Use a server-side proxy
// Client calls your backend
const response = await fetch('/api/proxy/users');
// Your backend adds the API key
// server.js
app.post('/api/proxy/users', async (req, res) => {
const response = await fetch('https://app.mlm-platform.com/api/v1/users', {
headers: {
'x-tenant-api-key': process.env.MLM_API_KEY // Secure!
},
body: JSON.stringify(req.body)
});
res.json(await response.json());
});
Use Environment Variables
Store API keys in environment variables:
# .env (never commit this file)
MLM_API_KEY=mlm_live_abc123...
MLM_SANDBOX_API_KEY=mlm_sandbox_xyz789...
// Use environment variables
const apiKey = process.env.NODE_ENV === 'production'
? process.env.MLM_API_KEY
: process.env.MLM_SANDBOX_API_KEY;
Rotate Keys Regularly
- Create a new API key
- Update your application to use the new key
- Verify the new key works
- Revoke the old key
Monitor Key Usage
Review API key usage in the Admin Dashboard:
- Request counts
- Error rates
- Last used timestamp
Environment Detection
Every API response includes an X-Environment header:
or
Use this to verify you’re hitting the correct environment:
const response = await fetch('/api/users', {
headers: { 'x-tenant-api-key': apiKey }
});
const environment = response.headers.get('X-Environment');
if (environment !== expectedEnvironment) {
console.warn(`Unexpected environment: ${environment}`);
}
The environment is derived from the API key used for the request.
You may include an X-Environment request header for debugging/explicitness, but the server will still derive the environment from the key.
Always treat the response header X-Environment as authoritative.
Error Responses
Missing API Key
{
"error": "Authentication required",
"code": "UNAUTHORIZED"
}
Invalid API Key
{
"error": "Invalid API key",
"code": "INVALID_API_KEY"
}
Revoked / Disabled API Key
Revoked/disabled keys are treated the same as invalid keys during validation.
{
"error": "Invalid API key",
"code": "INVALID_API_KEY"
}
Rate Limiting
API keys are subject to rate limiting:
| Response Header | Description |
|---|
X-RateLimit-Limit | Maximum requests per window |
X-RateLimit-Remaining | Requests remaining |
X-RateLimit-Reset | Unix timestamp when limit resets |
When rate limited, you’ll receive a 429 Too Many Requests response:
{
"error": "Rate limit exceeded. Try again in 60 seconds.",
"code": "RATE_LIMITED"
}
Handle rate limits gracefully:
async function makeRequest(url, options, retries = 3) {
const response = await fetch(url, options);
if (response.status === 429 && retries > 0) {
const retryAfter = response.headers.get('Retry-After') || 60;
await new Promise(r => setTimeout(r, retryAfter * 1000));
return makeRequest(url, options, retries - 1);
}
return response;
}
External Auth Providers (OIDC Federation)
For applications with existing user authentication, you can configure external auth providers to enable federated authentication. This allows users authenticated by your identity provider to access MLM Platform features without creating separate credentials.
When to Use External Auth Providers
- You have an existing user base with established authentication
- You want single sign-on (SSO) between your app and the MLM Platform
- You need to integrate MLM features into your existing application
How It Works
- User authenticates with your identity provider (IdP)
- Your app receives a JWT from your IdP
- Your app exchanges the JWT for MLM Platform tokens via
/api/v1/auth/exchange
- User can now access MLM Platform APIs with the exchanged tokens
Setting Up an External Auth Provider
External auth providers are configured per tenant. You can set them up:
- Via the Admin UI - Navigate to Developers > External Auth Providers
- Via the API - Use
POST /api/v1/admin/auth/providers
Required Configuration
| Field | Description | Example |
|---|
| Provider ID | Unique identifier used in API calls | my-app |
| Issuer URL | OIDC issuer URL (must be HTTPS) | https://auth.example.com |
| JWKS URI | JSON Web Key Set endpoint | https://auth.example.com/.well-known/jwks.json |
| Allowed Audiences | Valid aud claim values | ["api://my-app"] |
Creating Your JWKS File
A JSON Web Key Set (JWKS) is a JSON file containing the public keys used to verify JWT signatures. The MLM Platform fetches this file to validate tokens from your identity provider.
Option 1: Use Your Identity Provider’s JWKS
Most identity providers (Auth0, Okta, Azure AD, Firebase, etc.) automatically expose a JWKS endpoint:
| Provider | JWKS URI Format |
|---|
| Auth0 | https://YOUR_DOMAIN.auth0.com/.well-known/jwks.json |
| Okta | https://YOUR_DOMAIN.okta.com/oauth2/default/v1/keys |
| Azure AD | https://login.microsoftonline.com/YOUR_TENANT/discovery/v2.0/keys |
| Firebase | https://www.googleapis.com/service_accounts/v1/jwk/securetoken@system.gserviceaccount.com |
| Cognito | https://cognito-idp.REGION.amazonaws.com/USER_POOL_ID/.well-known/jwks.json |
Option 2: Generate Your Own JWKS
If you’re signing JWTs yourself, you’ll need to generate a key pair and create a JWKS file.
Using Node.js (jose library):
import { generateKeyPair, exportJWK } from 'jose';
import { randomUUID } from 'crypto';
async function generateJWKS() {
// Generate an RSA key pair
const { publicKey, privateKey } = await generateKeyPair('RS256');
// Export the public key as JWK
const publicJwk = await exportJWK(publicKey);
// Add required fields
const jwk = {
...publicJwk,
kid: randomUUID(), // Key ID - use this when signing JWTs
alg: 'RS256',
use: 'sig'
};
// Create the JWKS
const jwks = { keys: [jwk] };
console.log('JWKS (host this publicly):');
console.log(JSON.stringify(jwks, null, 2));
// Export private key for signing (keep this secret!)
const privateJwk = await exportJWK(privateKey);
console.log('\nPrivate key (keep secret):');
console.log(JSON.stringify({ ...privateJwk, kid: jwk.kid }, null, 2));
}
generateJWKS();
Using OpenSSL:
# Generate RSA private key
openssl genrsa -out private.pem 2048
# Extract public key
openssl rsa -in private.pem -pubout -out public.pem
# Convert to JWK format (use an online converter or jose library)
JWKS File Structure
Your JWKS file should look like this:
{
"keys": [
{
"kty": "RSA",
"kid": "unique-key-id",
"use": "sig",
"alg": "RS256",
"n": "base64url-encoded-modulus...",
"e": "AQAB"
}
]
}
Hosting Your JWKS
- Host the JWKS file at a publicly accessible HTTPS URL
- Ensure the URL returns
Content-Type: application/json
- The endpoint must be accessible without authentication
- Consider caching headers for performance (keys don’t change often)
Never include private keys in your JWKS file. Only public keys should be exposed.
Token Exchange Example
// Exchange your IdP token for MLM Platform tokens
const response = await fetch('https://app.mlm-platform.com/api/v1/auth/exchange', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Tenant-ID': 'your-tenant-id'
},
body: JSON.stringify({
provider: 'my-app', // Your provider ID
token: idpJwtToken // JWT from your identity provider
})
});
const { accessToken, refreshToken, expiresIn } = await response.json();
// Use accessToken for subsequent API calls
const userResponse = await fetch('https://app.mlm-platform.com/api/v1/members/me', {
headers: {
'Authorization': `Bearer ${accessToken}`
}
});
Auto-Create Users
When auto_create_users is enabled (default), users are automatically created in the MLM Platform on their first token exchange. The user’s email, name, and external ID are extracted from the JWT claims, so make sure these are correctly included in the JWT.