Skip to main content

SDK Authentication

Learn how to securely authenticate your applications with AxonFlow using OAuth2-style credentials and best practices for production deployments.

Installation

Install the AxonFlow SDK for your language to get started:

LanguageInstall CommandPackage
TypeScriptnpm install @axonflow/sdk@axonflow/sdk
Pythonpip install axonflowaxonflow
Gogo get github.com/getaxonflow/axonflow-sdk-go/v8axonflow-sdk-go
JavaAdd com.getaxonflow:axonflow-sdk:8.5.0 to pom.xmlMaven Central

For language-specific setup details, see Go SDK, Python SDK, TypeScript SDK, or Java SDK.

Overview

AxonFlow uses OAuth2-style Basic authentication for all deployments. Each organization uses a client ID (required) and client secret (optional for community mode) to authenticate API requests.

Authentication Header: Authorization: Basic base64(clientId:clientSecret)

Note: The client ID is recommended even for community/self-hosted deployments for request identification, metrics attribution, and audit logging. The client secret is only required for enterprise deployments.

Automatic headers the SDK sets for you

In addition to Authorization, the AxonFlow SDKs (TypeScript / Python / Go / Java) automatically set two headers on every governed request — you don't configure these:

HeaderValuePurpose
User-Agentaxonflow-sdk-<lang>/<version>Standard SDK identification used for compatibility checks against the platform's /health plugin-compatibility manifest.
X-Axonflow-Clientsdk-<lang>/<version> (e.g. sdk-typescript/7.8.0)Identifies which SDK is calling the agent so the platform can validate license-token scope (sdk vs plugin vs full) per the License Matrix. The value is sourced from the bundled SDK version constant — the consumer cannot spoof its own client identity through config.

The X-Axonflow-Client header is set automatically as of SDK v7.0.1 / v7.8.0 across all four SDKs. It only matters when you also send a Pro-tier X-License-Token (Community SaaS endpoints only); the agent validates the token's aud.scope matches the derived sdk scope before applying Pro-tier entitlements. For the rest of the auth model below, you can ignore it.

Getting Your Credentials

For AWS Marketplace Deployments (In-VPC)

After deploying AxonFlow via AWS CloudFormation:

  1. Credentials are automatically generated during deployment
  2. Find them in AWS Secrets Manager at: axonflow/customers/{your-org-id}/credentials
  3. Or check CloudFormation stack outputs for ClientID and ClientSecret

Retrieve via AWS CLI:

aws secretsmanager get-secret-value \
--secret-id axonflow/customers/your-org-id/credentials \
--region eu-central-1 \
--query 'SecretString' \
--output text | jq .

For Direct Purchases

Contact AxonFlow sales to receive your organization's credentials:

  • Email: [email protected]
  • Subject: "Credentials Request - [Your Organization]"
  • Response Time: 1 business day

You'll receive credentials via secure channel (encrypted email or AWS Secrets Manager).

Using Credentials

Free trial at try.getaxonflow.com

Set AXONFLOW_TRY=1 to auto-connect to the free trial server. Requires AXONFLOW_CLIENT_ID and AXONFLOW_CLIENT_SECRET from registration. No Docker or self-hosting needed.

TypeScript/JavaScript:

import { AxonFlow } from '@axonflow/sdk';

const axonflow = new AxonFlow({
clientId: process.env.AXONFLOW_CLIENT_ID,
clientSecret: process.env.AXONFLOW_CLIENT_SECRET, // Optional for community mode
endpoint: process.env.AXONFLOW_ENDPOINT
});

Go:

import (
"os"
"github.com/getaxonflow/axonflow-sdk-go/v8"
)

client := axonflow.NewClient(axonflow.AxonFlowConfig{
ClientID: os.Getenv("AXONFLOW_CLIENT_ID"),
ClientSecret: os.Getenv("AXONFLOW_CLIENT_SECRET"), // Optional for community mode
Endpoint: os.Getenv("AXONFLOW_ENDPOINT"),
})

Java:

import com.getaxonflow.sdk.AxonFlow;
import com.getaxonflow.sdk.AxonFlowConfig;

AxonFlowConfig config = AxonFlowConfig.builder()
.clientId(System.getenv("AXONFLOW_CLIENT_ID"))
.clientSecret(System.getenv("AXONFLOW_CLIENT_SECRET")) // Optional for community mode
.endpoint(System.getenv("AXONFLOW_ENDPOINT"))
.build();

AxonFlow client = AxonFlow.create(config);

Python:

import os
from axonflow import AxonFlow

client = AxonFlow(
client_id=os.getenv("AXONFLOW_CLIENT_ID"),
client_secret=os.getenv("AXONFLOW_CLIENT_SECRET"), # Optional for community mode
endpoint=os.getenv("AXONFLOW_ENDPOINT")
)

Environment file (.env):

# OAuth2 Credentials (Current Method)
AXONFLOW_CLIENT_ID=your-org-id
AXONFLOW_CLIENT_SECRET=your-secret-key
AXONFLOW_ENDPOINT=https://YOUR_VPC_IP:8443

# Or for the public community SaaS at try.getaxonflow.com
AXONFLOW_CLIENT_ID=your-org-id
AXONFLOW_CLIENT_SECRET=your-secret-key
AXONFLOW_ENDPOINT=https://try.getaxonflow.com

For production In-VPC deployments, store credentials in AWS Secrets Manager:

TypeScript (AWS SDK v3):

import { SecretsManagerClient, GetSecretValueCommand } from '@aws-sdk/client-secrets-manager';
import { AxonFlow } from '@axonflow/sdk';

async function getAxonFlowClient() {
const secretsManager = new SecretsManagerClient({ region: 'eu-central-1' });

const response = await secretsManager.send(
new GetSecretValueCommand({
SecretId: 'axonflow/customers/your-org-id/credentials'
})
);

const credentials = JSON.parse(response.SecretString!);

return new AxonFlow({
clientId: credentials.client_id,
clientSecret: credentials.client_secret,
endpoint: 'https://YOUR_VPC_IP:8443'
});
}

const axonflow = await getAxonFlowClient();

Go:

import (
"encoding/json"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/secretsmanager"
"github.com/getaxonflow/axonflow-sdk-go/v8"
)

type Credentials struct {
ClientID string `json:"client_id"`
ClientSecret string `json:"client_secret"`
}

func getAxonFlowClient() (*axonflow.AxonFlowClient, error) {
sess := session.Must(session.NewSession())
svc := secretsmanager.New(sess, aws.NewConfig().WithRegion("eu-central-1"))

result, err := svc.GetSecretValue(&secretsmanager.GetSecretValueInput{
SecretId: aws.String("axonflow/customers/your-org-id/credentials"),
})
if err != nil {
return nil, err
}

var creds Credentials
if err := json.Unmarshal([]byte(*result.SecretString), &creds); err != nil {
return nil, err
}

client := axonflow.NewClient(axonflow.AxonFlowConfig{
ClientID: creds.ClientID,
ClientSecret: creds.ClientSecret,
Endpoint: "https://YOUR_VPC_IP:8443",
})
return client, nil
}

Credential Configuration Reference

ParameterEnvironment VariableTypeRequiredDescription
clientId / ClientID / client_idAXONFLOW_CLIENT_IDstringYesYour API credential identifier. In v9 terminology, this is client_id — the credential/app identity inside your customer organization. Used for request attribution, metrics, and audit logging.
clientSecret / ClientSecret / client_secretAXONFLOW_CLIENT_SECRETstringEnterprise onlyAuthentication secret. Optional for community/self-hosted mode. Required for enterprise and SaaS deployments.
endpoint / EndpointAXONFLOW_ENDPOINTstringYesAxonFlow Agent URL. For the public community SaaS: https://try.getaxonflow.com. For In-VPC: https://YOUR_VPC_IP:8443.
tenant / TenantAXONFLOW_TENANTstringLegacy onlyDeprecated compatibility field. Prefer customer-specific clientId / clientSecret pairs or service-side credential lookup instead of new tenant-based examples. See v7 → v8 Migration Guide for the conceptual mapping.
v9 identity model
  • org_id = your customer organization (Row-Level-Security boundary in v9).
  • client_id = the API credential/app identity inside that org. This is the clientId you set in the SDK.
  • These were both called tenant_id in pre-v9 docs. The SDK already uses clientId correctly; the platform derives both org_id and client_id from the authenticated request. See Auth and Header Matrix — Identity Primer.

Security Best Practices

1. Never Hardcode Credentials

Bad:

const axonflow = new AxonFlow({
clientId: 'my-org-id', // Hardcoded!
clientSecret: 'secret-abc123' // Hardcoded!
});

Good:

const axonflow = new AxonFlow({
clientId: process.env.AXONFLOW_CLIENT_ID,
clientSecret: process.env.AXONFLOW_CLIENT_SECRET
});

2. Use Environment-Specific Credentials

Separate credentials for development, staging, and production:

# .env.development
AXONFLOW_CLIENT_ID=dev-org
AXONFLOW_CLIENT_SECRET=dev-secret

# .env.production
AXONFLOW_CLIENT_ID=prod-org
AXONFLOW_CLIENT_SECRET=prod-secret

3. Rotate Credentials Regularly

For production environments, rotate credentials every 90 days:

  1. Generate new credentials in AxonFlow dashboard
  2. Update environment variables/Secrets Manager
  3. Deploy updated configuration
  4. Revoke old credentials after 24 hours

4. Restrict Credential Permissions

In multi-tenant environments, use least-privilege credentials:

// Healthcare tenant only has access to healthcare policies
const healthcareAxonFlow = new AxonFlow({
clientId: process.env.HEALTHCARE_CLIENT_ID,
clientSecret: process.env.HEALTHCARE_CLIENT_SECRET,
});

// E-commerce tenant has separate access
const ecommerceAxonFlow = new AxonFlow({
clientId: process.env.ECOMMERCE_CLIENT_ID,
clientSecret: process.env.ECOMMERCE_CLIENT_SECRET,
});

5. Never Expose Credentials Client-Side

Never do this in React/Vue/Angular:

// THIS IS INSECURE - Don't put credentials in frontend code!
const axonflow = new AxonFlow({
clientId: 'my-org', // Exposed in browser!
clientSecret: 'secret-abc123' // Exposed in browser!
});

Instead, use a backend proxy:

// Frontend - calls your backend
const response = await fetch('/api/ai-query', {
method: 'POST',
body: JSON.stringify({ prompt })
});

// Backend API route - has credentials
import { AxonFlow } from '@axonflow/sdk';

const axonflow = new AxonFlow({
clientId: process.env.AXONFLOW_CLIENT_ID, // Safe - server-side only
clientSecret: process.env.AXONFLOW_CLIENT_SECRET,
endpoint: process.env.AXONFLOW_ENDPOINT
});

export default async function handler(req, res) {
const { prompt, userToken } = req.body;

// Use Proxy Mode for simple governance
const result = await axonflow.proxyLLMCall({
userToken: userToken || 'anonymous',
query: prompt,
requestType: 'chat'
});

res.json(result);
}

HTTP API Authentication

For direct HTTP API calls without an SDK, use Basic authentication:

# Create the Base64-encoded credentials
AUTH=$(echo -n 'your-client-id:your-client-secret' | base64)

# Make authenticated request
curl -X POST https://your-endpoint.com/api/v1/request \
-H "Authorization: Basic $AUTH" \
-H "Content-Type: application/json" \
-d '{
"query": "What is 2+2?",
"request_type": "chat"
}'

For community mode (no client secret):

# Use just the client ID
AUTH=$(echo -n 'your-client-id:' | base64)

curl -X POST https://your-endpoint.com/api/v1/request \
-H "Authorization: Basic $AUTH" \
-H "Content-Type: application/json" \
-d '{...}'

Multi-Tenant Authentication

For SaaS applications serving multiple tenants:

Tenant Isolation

import { AxonFlow } from '@axonflow/sdk';

// Initialize once per tenant
function getAxonFlowForTenant(tenantId: string) {
const tenant = resolveTenantCredentials(tenantId);
return new AxonFlow({
clientId: tenant.clientId,
clientSecret: tenant.clientSecret,
endpoint: tenant.endpoint
});
}

// Usage
const tenant1Client = getAxonFlowForTenant('healthcare-corp');
const tenant2Client = getAxonFlowForTenant('ecommerce-inc');

// Each client only sees their own policies and audit logs

Per-Tenant Credentials

For stricter isolation, use separate credentials per tenant. The column names in your application database are entirely yours — what matters at the AxonFlow boundary is the clientId you pass in:

// Your application's database schema (your column names, your choice)
{
your_tenant_key: 'healthcare-corp', // your application's tenant primary key
axonflow_client_id: 'healthcare-client', // maps to AxonFlow client_id (Basic Auth username)
axonflow_client_secret: 'healthcare-secret',
created_at: '2025-10-01'
}

// Retrieve from database
function getAxonFlowForTenant(yourTenantKey: string) {
const tenant = db.tenants.findOne({ your_tenant_key: yourTenantKey });

return new AxonFlow({
clientId: tenant.axonflow_client_id,
clientSecret: tenant.axonflow_client_secret,
endpoint: tenant.axonflow_endpoint
});
}

Common Authentication Issues

Issue 1: 401 Unauthorized

Cause: Invalid or missing credentials

Solution:

// Check credentials are set
console.log('Client ID:', process.env.AXONFLOW_CLIENT_ID?.substring(0, 10) + '...');

// Verify credentials are not empty
if (!process.env.AXONFLOW_CLIENT_ID) {
throw new Error('Missing AXONFLOW_CLIENT_ID');
}

Issue 2: 403 Forbidden

Cause: Credentials valid but lacks permissions

Solution:

  • Check tenant ID matches your credentials
  • Verify license tier supports requested features
  • Contact support to upgrade tier if needed

Issue 3: Connection Refused

Cause: Wrong endpoint URL

Solution:

For SaaS Mode:

const axonflow = new AxonFlow({
endpoint: 'https://try.getaxonflow.com' // Public community SaaS
});

For In-VPC Mode:

const axonflow = new AxonFlow({
endpoint: 'https://YOUR_VPC_IP:8443' // VPC private endpoint (replace YOUR_VPC_IP)
});

Testing Authentication

Quick Test (cURL)

# Test against the public community SaaS
curl -X POST https://try.getaxonflow.com/api/v1/request \
-H "Content-Type: application/json" \
-H "Authorization: Basic $(echo -n 'your-client-id:your-client-secret' | base64)" \
-d '{
"query": "What is 2+2?",
"request_type": "chat"
}'

# Expected: 200 OK with JSON response

Integration Test

TypeScript:

import { AxonFlow } from '@axonflow/sdk';

async function testAuthentication() {
const axonflow = new AxonFlow({
clientId: process.env.AXONFLOW_CLIENT_ID,
clientSecret: process.env.AXONFLOW_CLIENT_SECRET,
endpoint: process.env.AXONFLOW_ENDPOINT
});

try {
// Simple health check
const health = await axonflow.healthCheck();
console.log('Authentication successful');
return true;
} catch (error) {
console.error('Authentication failed:', error.message);
return false;
}
}

testAuthentication();

Go:

func testAuthentication() error {
client := axonflow.NewClient(axonflow.AxonFlowConfig{
Endpoint: os.Getenv("AXONFLOW_ENDPOINT"),
ClientID: os.Getenv("AXONFLOW_CLIENT_ID"),
ClientSecret: os.Getenv("AXONFLOW_CLIENT_SECRET"),
})

err := client.HealthCheck()
if err != nil {
return fmt.Errorf("authentication failed: %v", err)
}

fmt.Println("Authentication successful")
return nil
}

Legacy Authentication (Deprecated)

Warning: The licenseKey / LicenseKey parameter and X-License-Key header are deprecated as of November 2025 and will be removed after June 2026. Migrate to OAuth2 credentials (clientId/clientSecret) as shown in the examples above.

Migration summary:

  1. Replace AXONFLOW_LICENSE_KEY env var with AXONFLOW_CLIENT_ID and AXONFLOW_CLIENT_SECRET
  2. Update SDK initialization to use clientId/clientSecret (or ClientID/ClientSecret in Go) instead of licenseKey/LicenseKey
  3. Contact [email protected] with subject "OAuth2 Migration Request" to obtain your new credentials

Quick reference -- old vs new:

# OLD (remove)
AXONFLOW_LICENSE_KEY=AXON-ENT-xxx-yyy

# NEW (add)
AXONFLOW_CLIENT_ID=your-org-id
AXONFLOW_CLIENT_SECRET=your-secret-key

For detailed migration assistance, contact [email protected] or join #oauth2-migration on Slack.


Next Steps

Support

Having authentication issues?

Include in your support request:

  • SDK version (TypeScript/Go/Java/Python)
  • Deployment mode (SaaS or In-VPC)
  • Error message and stack trace
  • Client ID (first 10 characters only, never share secret)