Skip to main content

Authentication

All API requests to the MLM Platform require authentication using a tenant API key.

API Key Format

API keys are passed in the x-tenant-api-key HTTP header:
x-tenant-api-key: mlm_live_abc123...

Key Types

PrefixEnvironmentUsage
mlm_live_LIVEProduction data
mlm_sandbox_SANDBOXTesting and development
Never use LIVE keys in development or testing environments.

Creating API Keys

  1. Navigate to Settings > API Keys in the Admin Dashboard
  2. Click Create API Key
  3. Select the environment (LIVE or SANDBOX)
  4. Add an optional description
  5. 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

  1. Create a new API key
  2. Update your application to use the new key
  3. Verify the new key works
  4. 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:
X-Environment: LIVE
or
X-Environment: SANDBOX
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 HeaderDescription
X-RateLimit-LimitMaximum requests per window
X-RateLimit-RemainingRequests remaining
X-RateLimit-ResetUnix 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

  1. User authenticates with your identity provider (IdP)
  2. Your app receives a JWT from your IdP
  3. Your app exchanges the JWT for MLM Platform tokens via /api/v1/auth/exchange
  4. 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:
  1. Via the Admin UI - Navigate to Developers > External Auth Providers
  2. Via the API - Use POST /api/v1/admin/auth/providers

Required Configuration

FieldDescriptionExample
Provider IDUnique identifier used in API callsmy-app
Issuer URLOIDC issuer URL (must be HTTPS)https://auth.example.com
JWKS URIJSON Web Key Set endpointhttps://auth.example.com/.well-known/jwks.json
Allowed AudiencesValid 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:
ProviderJWKS URI Format
Auth0https://YOUR_DOMAIN.auth0.com/.well-known/jwks.json
Oktahttps://YOUR_DOMAIN.okta.com/oauth2/default/v1/keys
Azure ADhttps://login.microsoftonline.com/YOUR_TENANT/discovery/v2.0/keys
Firebasehttps://www.googleapis.com/service_accounts/v1/jwk/securetoken@system.gserviceaccount.com
Cognitohttps://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

  1. Host the JWKS file at a publicly accessible HTTPS URL
  2. Ensure the URL returns Content-Type: application/json
  3. The endpoint must be accessible without authentication
  4. 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.
For detailed configuration options and troubleshooting, see the External Auth Providers Guide.