Skip to content

Authentication

CertusOrdo uses a two-layer authentication system: API keys for organization-level operations and JWT tokens for agent operations.

Authentication Overview

Layer Credential Use Case Lifetime
Organization API Key Create agents, manage org Permanent (until rotated)
Agent JWT Token Execute operations 1 hour (access), 7 days (refresh)

API Key Authentication

API keys authenticate your organization for administrative operations.

Getting Your API Key

API keys are generated when you create an organization:

import httpx

response = httpx.post(
    "https://web-production-b910f.up.railway.app/v1/organizations",
    json={"name": "My Company"}
)

data = response.json()
api_key = data["api_key"]  # aa_xxxxx... - Save this!

API Key Security

  • API keys are only shown once at creation
  • Store securely (environment variables, secrets manager)
  • Never commit to version control
  • Rotate immediately if compromised

Using API Keys

Include the API key in the X-API-Key header:

from certusrodo import CertusOrdoClient

# SDK handles this automatically
client = CertusOrdoClient(api_key="aa_your_api_key")

# Or manually with httpx/requests
headers = {"X-API-Key": "aa_your_api_key"}
response = httpx.get(
    "https://web-production-b910f.up.railway.app/v1/agents",
    headers=headers
)

Agent JWT Authentication

Agents authenticate using JWT tokens obtained by exchanging their credentials.

Authentication Flow

┌─────────┐                    ┌───────────┐
│  Agent  │                    │ CertusOrdo│
└────┬────┘                    └─────┬─────┘
     │                               │
     │  POST /v1/auth/token          │
     │  {agent_id, secret}           │
     │──────────────────────────────>│
     │                               │
     │  {access_token, refresh_token}│
     │<──────────────────────────────│
     │                               │
     │  GET /v1/... + Bearer token   │
     │──────────────────────────────>│
     │                               │

Getting Tokens

from certusrodo import CertusOrdoClient

client = CertusOrdoClient(api_key="aa_your_api_key")

# Create an agent first
agent = client.agents.create(
    name="my-agent",
    scopes=["read", "write"]
)

# Exchange credentials for tokens
tokens = client.auth.get_token(
    agent_id=agent.id,
    secret=agent.secret
)

print(f"Access Token: {tokens.access_token}")
print(f"Refresh Token: {tokens.refresh_token}")
print(f"Expires In: {tokens.expires_in} seconds")

Token Contents

The JWT access token contains:

{
  "agent_id": "uuid",
  "org_id": "uuid",
  "scopes": ["read", "write"],
  "iat": 1705420800,
  "exp": 1705424400
}

Using Tokens

# SDK handles token management automatically
tokens = client.auth.get_token(agent_id=agent.id, secret=agent.secret)

# Tokens are now used for subsequent operations
txn = client.transactions.begin(
    pre_state={"data": "value"},
    action_type="update"
)

Refreshing Tokens

Access tokens expire after 1 hour. Use refresh tokens to get new ones:

# When access token expires
new_tokens = client.auth.refresh_token(refresh_token=tokens.refresh_token)

print(f"New Access Token: {new_tokens.access_token}")

Revoking Tokens

Revoke tokens when an agent should no longer have access:

# Revoke a specific refresh token
client.auth.revoke_token(refresh_token=tokens.refresh_token)

Scopes

Scopes define what an agent can do. Define them at agent creation:

agent = client.agents.create(
    name="read-only-agent",
    scopes=["data:read"]  # Can only read, not write
)

agent = client.agents.create(
    name="full-access-agent",
    scopes=["data:read", "data:write", "admin:manage"]
)

Common Scope Patterns

Scope Permission
read Read-only access
write Create and update
delete Delete resources
admin Administrative operations
transactions:rollback Can initiate rollbacks

Security Best Practices

1. Use Environment Variables

import os
from certusrodo import CertusOrdoClient

client = CertusOrdoClient(
    api_key=os.environ["CERTUSRODO_API_KEY"]
)

2. Implement Token Refresh Logic

from datetime import datetime, timedelta

class AgentAuth:
    def __init__(self, client, agent_id, secret):
        self.client = client
        self.agent_id = agent_id
        self.secret = secret
        self.tokens = None
        self.token_expiry = None

    def get_valid_token(self):
        # Check if token needs refresh
        if self.tokens is None or datetime.now() >= self.token_expiry:
            self.refresh()
        return self.tokens.access_token

    def refresh(self):
        if self.tokens and self.tokens.refresh_token:
            try:
                self.tokens = self.client.auth.refresh_token(
                    self.tokens.refresh_token
                )
            except:
                # Refresh token expired, get new tokens
                self.tokens = self.client.auth.get_token(
                    self.agent_id, self.secret
                )
        else:
            self.tokens = self.client.auth.get_token(
                self.agent_id, self.secret
            )

        # Set expiry with 5-minute buffer
        self.token_expiry = datetime.now() + timedelta(
            seconds=self.tokens.expires_in - 300
        )

3. Revoke Compromised Credentials

# If agent secret is compromised, revoke the agent
client.agents.revoke(agent.id)

# Create a new agent with fresh credentials
new_agent = client.agents.create(
    name="my-agent-v2",
    scopes=["read", "write"]
)

Error Handling

from certusrodo import CertusOrdoClient, AuthenticationError

client = CertusOrdoClient(api_key="aa_your_key")

try:
    tokens = client.auth.get_token(
        agent_id="invalid-id",
        secret="wrong-secret"
    )
except AuthenticationError as e:
    print(f"Authentication failed: {e}")

Next Steps