Hessra Logo
< BACK_TO_DOCS
#identity-tokens#getting-started#documentation#authentication#delegation

Getting Started with Hessra Identity

Learn how to use Hessra Identity tokens for secure machine authentication, replacing static API keys and refresh tokens with cryptographically delegatable identities.

by The Hessra Team

Getting Started with Hessra Identity

Hessra Identity tokens provide a modern approach to machine authentication. Unlike traditional API keys or JWTs, identity tokens prove who you are without granting any permissions. They're cryptographically delegatable, letting you create hierarchical identity chains without contacting a central authority.

> When to Use Identity Tokens

Identity tokens excel in scenarios where you need:

Opaque Token Replacement

  • OAuth Refresh Tokens: Instead of long-lived tokens with broad permissions
  • Static API Keys: Replace copy-pasted secrets with time-bounded, delegatable identities
  • Service Accounts: Give services identity without ambient authority

Ephemeral Identities

  • AI Agents and Sub-agents: Create delegation chains for autonomous systems
  • CI/CD Pipeline Jobs: Scope identity to specific build or deployment tasks
  • Temporary Access: Grant contractors or tools time-limited identity

> Core Concepts

Identity vs Authorization

  • Identity Token: Proves WHO you are (like a passport)
  • Authorization Token: Grants WHAT you can do (like a ticket)

Identity tokens carry no permissions. They're used to authenticate when requesting authorization tokens. You can also use Hessra identity tokens without Hessra authorization. This is a great option if you already have a robust self-made authorization system or already rely on a policy engine like SpiceDB or OPA.

Delegation Chains

Identity tokens can be delegated offline, creating a verifiable chain:

alice → alice:agent → alice:agent:worker

Each level can only act as itself and delegate further down. The worker cannot impersonate the agent or alice.

> Installation

Hessra CLI

# macOS/Linux
curl -L https://releases.hessra.net/cli/latest | bash

# Or with cargo
cargo install hessra

Rust SDK

[dependencies]
hessra-sdk = "0.10.0"

Python SDK

pip install hessra-py

> Basic Usage

1. Obtain Your First Identity Token

Authenticate using mTLS certificates to get your root identity:

# Using the CLI
hessra identity authenticate \
  --server auth.your-domain.com \
  --cert client.crt \
  --key client.key \
  --ca ca.crt \
  --ttl 86400 \
  --save-as my-identity

# Response:
# ✓ Identity token saved as 'my-identity'
# Identity: urn:hessra:alice
# Expires in: 86400 seconds

Or programmatically with Rust:

use hessra_sdk::{Hessra, Protocol};

let mut client = Hessra::builder()
    .base_url("auth.your-domain.com")
    .mtls_cert(client_cert)
    .mtls_key(client_key)
    .server_ca(ca_cert)
    .build()?;

// Request identity token (no resource/operation needed)
let response = client.request_identity_token(None).await?;

if let Some(token) = response.token {
    println!("Identity: {}", response.identity.unwrap());
    println!("Token received: {}...", &token[..50]);
}

2. Verify Identity Tokens

Verification happens locally without network calls:

// Verify the token matches the claimed identity
client.verify_identity_token_local(
    &token,
    "urn:hessra:alice"
)?;

With the CLI:

hessra identity verify \
  --token-name my-identity \
  --identity "urn:hessra:alice"

# ✓ Identity token is valid

3. Delegate Identity

Create a more restricted identity token for a sub-component:

# Create delegated identity for an agent
hessra identity delegate \
  --from-token my-identity \
  --identity "urn:hessra:alice:data-processor" \
  --ttl 3600 \
  --save-as agent-identity

In Rust:

// Attenuate the token to a new identity
let delegated_token = client.attenuate_identity_token(
    &parent_token,
    "urn:hessra:alice:data-processor",
    3600  // 1 hour
)?;

// The delegated token can only be used as alice:data-processor
client.verify_identity_token_local(
    &delegated_token,
    "urn:hessra:alice:data-processor"
)?;

4. Use Identity for Authorization

Once you have an identity token, use it instead of mTLS for requesting authorization:

// Create client with identity token instead of mTLS
let client = Hessra::builder()
    .base_url("auth.your-domain.com")
    .identity_token(&identity_token)  // Use identity token
    .server_ca(ca_cert)  // Still need CA for server verification
    .build()?;

// Request authorization token
let auth_token = client
    .request_token("database", "read")
    .await?;

Python example:

import hessra_py

# Build client without mTLS certificates
client = (
    hessra_py.HessraClient.builder()
    .base_url("auth.your-domain.com")
    .server_ca(ca_cert)
    .build()
)

# Use identity token for authentication
auth_token = client.request_token_with_identity(
    resource="database",
    operation="read",
    identity_token=identity_token
)

> Advanced Patterns

Hierarchical Agent Systems

Build complex delegation hierarchies for AI agents:

class AgentOrchestrator:
    def __init__(self, base_identity_token):
        self.identity_token = base_identity_token
        self.identity = "urn:hessra:system:orchestrator"

    def spawn_agent(self, agent_type, task_id):
        # Create agent-specific identity
        agent_identity = f"{self.identity}:{agent_type}:{task_id}"

        # Delegate identity with appropriate TTL
        agent_token = self.delegate_identity(
            agent_identity,
            ttl=300  # 5 minutes for task
        )

        # Spawn agent with its identity
        if agent_type == "analyzer":
            return AnalyzerAgent(agent_identity, agent_token)
        elif agent_type == "executor":
            return ExecutorAgent(agent_identity, agent_token)

Pipeline Identity Scoping

Scope CI/CD pipeline identities to specific stages:

# .github/workflows/deploy.yml
steps:
  - name: Create build identity
    run: |
      hessra identity delegate \
        --from-token ${{ secrets.PIPELINE_IDENTITY }} \
        --identity "urn:hessra:ci:${{ github.run_id }}:build" \
        --ttl 600 \
        --save-as build-identity

  - name: Build with scoped identity
    run: |
      export HESSRA_IDENTITY=$(cat build-identity)
      ./build.sh

  - name: Create deploy identity
    run: |
      hessra identity delegate \
        --from-token ${{ secrets.PIPELINE_IDENTITY }} \
        --identity "urn:hessra:ci:${{ github.run_id }}:deploy" \
        --ttl 300 \
        --save-as deploy-identity

Refresh Patterns

Identity tokens can be refreshed before expiration:

// Check if token needs refresh (< 10 minutes remaining)
if token_expires_in < 600 {
    let refreshed = client
        .refresh_identity_token(&current_token)
        .await?;

    // Update stored token
    update_token_storage(refreshed.token);
}

Delegation Policies

Control what delegated identities can do using embedded Datalog policies:

// When creating a delegated token, add constraints
let restricted_token = client.attenuate_identity_token_with_policy(
    &parent_token,
    "urn:hessra:alice:reader",
    3600,
    // This delegated identity can only request read operations
    "check if operation($op), $op == \"read\";"
)?;

> Configuring Identity Delegation with GitOps

Hessra uses a GitOps approach for managing identity and authorization policies. Your configuration lives in TOML files in a git repository, providing versioned, auditable control over who can authenticate and what delegations are allowed.

Setting Up Client Identity Permissions

In your clients.toml, define which identities can authenticate and use identity tokens:

# CA certificates that can authenticate clients
[cacerts]
cert_chain = '''-----BEGIN CERTIFICATE-----
...your CA certificates...
-----END CERTIFICATE-----'''

# Define a root identity that can use identity tokens
[[clients]]
identifier = { type = "san_uri", value = "uri:urn:company:alice" }
resources = [
  { name = "production_api", operations = ["read", "write"] },
  { name = "staging_api", operations = ["read", "write"] }
]
identity_token_enabled = true
identity_token_duration = 28800  # 8 hours

# Define a delegated identity with reduced permissions
[[clients]]
identifier = { type = "san_uri", value = "uri:urn:company:alice:agent1" }
resources = [
  { name = "production_api", operations = ["read"] }  # Read-only access
]
identity_token_enabled = true
identity_token_duration = 3600  # 1 hour - shorter lived

Controlling Delegation Chains

The configuration automatically validates delegation hierarchies. In the example above:

  • alice can authenticate with mTLS and get an 8-hour identity token
  • alice can delegate to alice:agent1
  • alice:agent1 automatically has reduced permissions (read-only)
  • alice:agent1 gets shorter-lived tokens (1 hour)

Any identity not defined in the configuration won't be accepted by the authorization service, even if cryptographically valid. This gives you central control over your delegation trees.

GitOps Workflow

  1. Version Control: All changes to clients.toml are tracked in git
  2. Review Process: Policy changes go through PR review
  3. Automatic Sync: The authorization service pulls updates from your repository
  4. Audit Trail: Complete history of who changed what and when

This approach ensures that identity delegation isn't just cryptographically secure but also organizationally controlled.

> Security Best Practices

Token Lifetime Guidelines

Balance security with operational needs:

Token TypeRecommended TTLUse Case
Human Identity8-24 hoursDeveloper workstations
Service Identity1-8 hoursLong-running services
Agent Identity5-60 minutesAutonomous agents
Task Identity1-5 minutesSingle operations

For services and jobs, picking a TTL is basically the halting problem in operating system scheduling. It's impossible to know exactly how long something will take, so pick a safe bound.

Secure Token Storage

Never store tokens in:

  • Source code
  • Configuration files
  • Logs or debug output

Instead use:

  • Environment variables (for containers)
  • Secure key stores (for persistent storage)
  • Memory (for ephemeral use)

Delegation Naming Conventions

Use consistent, hierarchical naming:

urn:hessra:{principal}:{service}:{component}:{subcomponent}

This makes audit logs clear and enables pattern-based policies.

Rotation Strategies

Implement automatic rotation:

// Background task to refresh identity
tokio::spawn(async move {
    loop {
        tokio::time::sleep(Duration::from_secs(3600)).await;

        match client.refresh_identity_token(&current_token).await {
            Ok(new_token) => update_token(new_token),
            Err(e) => log::error!("Token refresh failed: {}", e),
        }
    }
});

> Integration Examples

With Authorization Tokens

Identity tokens authenticate you to request authorization:

// Step 1: Get identity token (once per session)
let identity_response = client.request_identity_token(None).await?;
let identity_token = identity_response.token.unwrap();

// Step 2: Use identity for authorization requests
let auth_client = Hessra::builder()
    .base_url("auth.your-domain.com")
    .identity_token(&identity_token)
    .server_ca(ca_cert)
    .build()?;

// Step 3: Request specific authorizations as needed
let read_token = auth_client.request_token("database", "read").await?;
let write_token = auth_client.request_token("database", "write").await?;

With Service Chains

Identity tokens work seamlessly with service chain attestation:

// Each service in the chain has its identity
let service_identity = "urn:hessra:services:api-gateway";
let service_token = get_identity_token(service_identity);

// Attest the authorization token at this hop
let attested = client.attest_service_chain_token(
    auth_token,
    service_identity
)?;

// Forward to next service with both identity and authorization
next_service.call_with_tokens(service_token, attested);

> Troubleshooting

Common Issues

Token Verification Fails

Error: Token identity mismatch
  • Ensure the identity in verification matches the token's delegated identity
  • Check token hasn't expired
  • Verify delegation chain is valid

Cannot Delegate Further

Error: Maximum delegation depth reached
  • Biscuit tokens have a maximum delegation depth (default: 10)
  • Redesign to use flatter hierarchies if hitting limits

Identity Token Rejected

Error: Identity token not accepted for this operation
  • Some operations may require mTLS authentication
  • Check service configuration for identity token support

Debug Commands

# Inspect a token's details
hessra identity verify --token-name my-identity --verbose

# List all stored tokens
hessra identity list

# Check token expiration
hessra identity verify --token-name my-identity --check-expiry

> Next Steps

Now that you understand identity tokens:

  1. Explore authorization tokens for permission grants
  2. Learn about service chains for distributed authorization
  3. Check our SDK documentation for detailed API references
  4. See GitHub examples for complete implementations

Questions about identity tokens? Contact us at hello@hessra.net or join our community.