Table of Contents

Agent Access Tokens

This document provides a comprehensive reference for FoundationaLLM Agent Access Tokens (AATs), covering their purpose, architecture, token lifecycle, security model, and API surface.

Overview

Agent Access Tokens provide a secure, non-Entra ID authentication mechanism that allows unauthenticated users to interact with FoundationaLLM agents. This is particularly useful for public-facing applications where requiring users to authenticate with Azure Entra ID credentials is not practical or desired.

When a client presents a valid Agent Access Token, the platform creates a virtual identity with scoped permissions, allowing the token holder to create sessions and request completions against the associated agent — without ever signing in through an identity provider.

Key Characteristics

Characteristic Description
Scope Each token is bound to a single agent.
Identity Token holders receive a virtual identity with group-based RBAC.
Expiration Tokens support optional expiration dates.
Revocability Tokens can be deactivated or deleted at any time.
Transport Tokens are passed in the X-AGENT-ACCESS-TOKEN HTTP header.
Format Tokens use a Base58-encoded, secret-key structure with prefix and suffix delimiters.

Core Concepts

Token Structure

An Agent Access Token is a serialized ClientSecretKey that encodes four components:

keya.{Base58(InstanceId)}.{Base58(ContextId)}.{Base58(Id)}.{ClientSecret}.ayek
Component Description
keya / ayek Fixed prefix and suffix delimiters that identify the token format.
InstanceId The FoundationaLLM deployment instance identifier, Base58-encoded.
ContextId Encodes the resource path: {InstanceId}~FoundationaLLM.Agent~Agents~{AgentName}. Base58-encoded.
Id A unique identifier (GUID) for this specific token, Base58-encoded.
ClientSecret The cryptographic secret used for server-side validation.

The ContextId follows a hierarchical format that ties the token to a specific agent within a specific instance:

{InstanceId}~FoundationaLLM.Agent~Agents~{AgentName}

This structure ensures that each token is intrinsically bound to both the deployment instance and the target agent, preventing token reuse across agents or environments.

Virtual Identity

When a token is validated successfully, the platform constructs a virtual identity (UnifiedUserIdentity) that represents the token holder throughout the request pipeline:

Property Value Description
UserId Token ID (GUID) Unique identifier derived from the token.
Name Token ID (GUID) Display name for audit and logging purposes.
Username Token ID (GUID) Internal username.
UPN aat_{AgentName}_{TokenId}@foundationallm.internal_ A synthetic User Principal Name that identifies this as an AAT-based identity.
GroupIds [VirtualSecurityGroupId, AllAgentsVirtualSecurityGroup] Group memberships that drive RBAC authorization.

The virtual identity is injected into the request's claims principal, making it indistinguishable from a regular authenticated user from the perspective of downstream services.

Virtual Security Groups

Every agent in FoundationaLLM has a Virtual Security Group ID — a GUID that is automatically generated when the agent is first created. All tokens issued for a given agent share the same Virtual Security Group membership, which enables uniform RBAC policy enforcement.

graph TD
    subgraph "Agent: customer-support"
        Agent["Agent Resource"]
        VSID["Virtual Security Group ID<br/>(auto-generated GUID)"]
    end

    subgraph "Agent Access Tokens"
        T1["Token A"]
        T2["Token B"]
        T3["Token C"]
    end

    subgraph "RBAC"
        RA["Role Assignment<br/>Role: Reader<br/>Principal: VSID<br/>Scope: agents/customer-support"]
    end

    Agent --- VSID
    T1 -->|member of| VSID
    T2 -->|member of| VSID
    T3 -->|member of| VSID
    VSID -->|granted by| RA

In addition to the agent-specific Virtual Security Group, every AAT virtual identity is also a member of the All Agents Virtual Security Group, which can be used for platform-wide policies that apply to all token-authenticated users.


Token Lifecycle

The following diagram illustrates the complete lifecycle of an Agent Access Token:

stateDiagram-v2
    [*] --> Created: Administrator creates token<br/>via Management Portal or API
    Created --> Active: Token stored with<br/>Active = true
    Active --> InUse: Client presents token<br/>in X-AGENT-ACCESS-TOKEN header
    InUse --> Active: Request completes
    Active --> Expired: ExpirationDate reached
    Active --> Deleted: Administrator deletes token
    Expired --> [*]
    Deleted --> [*]

Creation

Tokens are created through the Management API or Management Portal. The creation process:

  1. The administrator specifies a description and an optional expiration date.
  2. The platform generates a unique Id (GUID) and a ClientSecret.
  3. An AgentAccessToken resource is created with Active = true.
  4. The token is stored via the authorization service using UpsertSecretKey.
  5. The full ClientSecretString (the token value) is returned once and must be saved by the administrator — it cannot be retrieved again.

Validation

Each time a client sends a request with an AAT, the following validation steps are performed:

  1. Format validation — The token string is parsed to extract InstanceId, ContextId, Id, and ClientSecret. Invalid format results in immediate rejection.
  2. Token lookup — The system loads all tokens for the agent identified in the ContextId and verifies that a token with the matching Id exists.
  3. Expiration check — If the token has an ExpirationDate, it is compared against the current UTC time.
  4. Active check — The token's Active flag must be true.
  5. Agent match — The agent name extracted from the token must match the agent associated with the loaded tokens.
  6. Cryptographic validation — The ClientSecret is validated against the stored secret via the authorization service.

If all checks pass, a virtual identity is constructed and injected into the request pipeline.

Deletion

Tokens can be deleted by an administrator through the Management API. Deletion removes the token from the authorization service. Any subsequent requests using the deleted token will fail validation.


Authentication Flow

The following diagram shows how a client request with an Agent Access Token flows through the FoundationaLLM platform:

sequenceDiagram
    participant Client
    participant CoreAPI as Core API
    participant AuthHandler as AgentAccessToken<br/>AuthenticationHandler
    participant AgentRP as Agent Resource<br/>Provider
    participant AuthService as Authorization<br/>Service

    Client->>CoreAPI: POST /completions<br/>Header: X-AGENT-ACCESS-TOKEN: keya...ayek
    CoreAPI->>AuthHandler: Authentication middleware intercepts request

    AuthHandler->>AuthHandler: Extract token from<br/>X-AGENT-ACCESS-TOKEN header
    AuthHandler->>AuthHandler: Parse token format<br/>(keya.{...}.{...}.{...}.{...}.ayek)

    AuthHandler->>AgentRP: POST /agents/{agentName}/<br/>agent-access-tokens/validate
    AgentRP->>AgentRP: Load agent tokens
    AgentRP->>AgentRP: Verify token exists,<br/>not expired, active
    AgentRP->>AuthService: ValidateSecretKey<br/>(cryptographic check)
    AuthService-->>AgentRP: Validation result

    AgentRP->>AgentRP: Build UnifiedUserIdentity<br/>with VirtualSecurityGroupId
    AgentRP-->>AuthHandler: AgentAccessTokenValidationResult<br/>(Valid + VirtualIdentity)

    AuthHandler->>AuthHandler: Create ClaimsPrincipal<br/>with identity claims

    Note over AuthHandler: Claims include:<br/>Name, ObjectId, UPN,<br/>Scope (Data.Read),<br/>Group memberships

    AuthHandler-->>CoreAPI: AuthenticateResult.Success<br/>(ClaimsPrincipal)
    CoreAPI->>CoreAPI: Process request with<br/>virtual identity
    CoreAPI-->>Client: Completion response

Claims Mapping

When authentication succeeds, the following claims are set on the request principal:

Claim Source Description
Name VirtualIdentity.Name The token ID, used as the display name.
Oid VirtualIdentity.UserId Object identifier claim.
ObjectId VirtualIdentity.UserId Duplicate of Oid for compatibility.
PreferredUserName VirtualIdentity.UPN The synthetic UPN (aat_{agent}_{tokenId}@foundationallm.internal_).
Scope "Data.Read" The permission scope granted to the token holder.
Groups VirtualIdentity.GroupIds One claim per group: the agent's Virtual Security Group ID and the All Agents Virtual Security Group.

API Reference

Create an Agent Access Token

Creates a new access token for the specified agent.

POST /instances/{instanceId}/providers/FoundationaLLM.Agent/agents/{agentName}/agent-access-tokens

Request Body

{
    "type": "agent-access-token",
    "name": "my-token",
    "description": "Token for public chat widget",
    "expiration_date": "2025-12-31T23:59:59Z"
}
Field Type Required Description
type string Yes Must be "agent-access-token".
name string Yes A descriptive name for the token.
description string No Human-readable description of the token's purpose.
expiration_date string No ISO 8601 date-time after which the token is no longer valid.

Response

The response contains the ClientSecretString — the full token value. This value is returned only once and cannot be retrieved again.

{
    "object_id": "/instances/{instanceId}/providers/FoundationaLLM.Agent/agents/{agentName}/agent-access-tokens/{tokenId}",
    "resource_object_id": null,
    "is_success": true
}

Important: Copy and securely store the token immediately after creation. It cannot be retrieved later.


List Agent Access Tokens

Retrieves all access tokens for the specified agent. The response includes token metadata but not the secret values.

GET /instances/{instanceId}/providers/FoundationaLLM.Agent/agents/{agentName}/agent-access-tokens

Response

[
    {
        "resource": {
            "type": "agent-access-token",
            "name": "my-token",
            "object_id": "/instances/{instanceId}/providers/FoundationaLLM.Agent/agents/{agentName}/agent-access-tokens/{tokenId}",
            "id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
            "active": true,
            "description": "Token for public chat widget",
            "expiration_date": "2025-12-31T23:59:59Z"
        }
    }
]

Validate an Agent Access Token

Validates a token and returns the associated virtual identity.

POST /instances/{instanceId}/providers/FoundationaLLM.Agent/agents/{agentName}/agent-access-tokens/validate

Request Body

{
    "access_token": "keya.{...}.{...}.{...}.{...}.ayek"
}

Response

{
    "valid": true,
    "virtual_identity": {
        "user_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
        "name": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
        "upn": "aat_myagent_xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx@foundationallm.internal_",
        "group_ids": [
            "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
            "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy"
        ]
    }
}

Delete an Agent Access Token

Permanently removes an access token.

DELETE /instances/{instanceId}/providers/FoundationaLLM.Agent/agents/{agentName}/agent-access-tokens/{tokenId}

Response

Returns 204 No Content on success.


Using an Agent Access Token

To use an Agent Access Token, clients include the token value in the X-AGENT-ACCESS-TOKEN HTTP header on requests to the Core API. No other authentication (such as a Bearer token) is required.

Creating a Session

POST /instances/{instanceId}/sessions HTTP/1.1
Host: {core-api-host}
X-AGENT-ACCESS-TOKEN: keya.{...}.{...}.{...}.{...}.ayek
Content-Type: application/json

{
    "name": "My Chat Session"
}

Requesting a Completion

POST /instances/{instanceId}/completions HTTP/1.1
Host: {core-api-host}
X-AGENT-ACCESS-TOKEN: keya.{...}.{...}.{...}.{...}.ayek
Content-Type: application/json

{
    "session_id": "{sessionId}",
    "user_prompt": "What can you help me with?"
}

The following diagram summarizes how a public client application interacts with FoundationaLLM using an Agent Access Token:

sequenceDiagram
    participant User as Public User
    participant App as Client Application
    participant API as Core API

    Note over User,API: No Entra ID login required

    User->>App: Opens chat interface
    App->>API: POST /sessions<br/>X-AGENT-ACCESS-TOKEN: keya...ayek
    API-->>App: { session_id: "abc-123" }

    User->>App: Sends message
    App->>API: POST /completions<br/>X-AGENT-ACCESS-TOKEN: keya...ayek<br/>{ session_id: "abc-123",<br/>  user_prompt: "Hello!" }
    API-->>App: { text: "Hi! How can I help?" }
    App-->>User: Displays response

Security Model

RBAC Integration

Agent Access Tokens integrate with the FoundationaLLM role-based access control (RBAC) system through Virtual Security Groups. The following diagram illustrates the authorization model:

graph LR
    subgraph "Token Authentication"
        Token["Agent Access Token"]
        VI["Virtual Identity"]
    end

    subgraph "Group Membership"
        VSG["Agent Virtual<br/>Security Group"]
        AVSG["All Agents Virtual<br/>Security Group"]
    end

    subgraph "Role Assignment"
        RA["Reader Role<br/>on Agent Resource"]
    end

    subgraph "Permissions"
        P1["Create Sessions"]
        P2["Request Completions"]
        P3["Read Agent Config"]
    end

    Token -->|validates to| VI
    VI -->|member of| VSG
    VI -->|member of| AVSG
    VSG -->|assigned| RA
    RA -->|grants| P1
    RA -->|grants| P2
    RA -->|grants| P3

To enable access for AAT holders, an administrator must create a role assignment:

  1. Copy the agent's Virtual Security Group ID from the agent configuration.
  2. Navigate to the agent's Access Control page.
  3. Create a new role assignment with:
    • Scope: providers/FoundationaLLM.Agent/agents/{agent_name}
    • Principal Type: Group
    • Principal ID: The Virtual Security Group ID
    • Role: Reader

Required RBAC Role for Token Management

Creating and managing Agent Access Tokens requires the Agent Access Tokens Contributor role, which grants the following permissions:

Action Description
read List and view agent access tokens.
write Create new agent access tokens.
delete Remove agent access tokens.
validate Validate agent access tokens.

Security Considerations

Consideration Details
Token secrecy Tokens are displayed only once at creation time. They must be stored securely by the administrator.
Expiration Always set an expiration date for production tokens to limit exposure in case of compromise.
Least privilege Tokens grant Data.Read scope only. They cannot modify agent configurations or access other agents.
Revocation Compromised tokens can be deleted immediately, and all subsequent requests using them will fail.
Audit trail All requests made with AATs are logged with the synthetic UPN, enabling tracing of token-based activity.
Instance isolation Tokens encode the FoundationaLLM instance ID, preventing cross-environment reuse.
Agent isolation Each token is cryptographically bound to a specific agent and cannot be used with other agents.

Data Model Reference

AgentAccessToken

Represents a stored access token resource.

Property Type Description
Id Guid Unique identifier for the token.
Active bool Whether the token is currently active.
Name string Descriptive name for the token (inherited from ResourceBase).
Description string Human-readable description (inherited from ResourceBase).
ExpirationDate DateTimeOffset? Optional expiration date (inherited from ResourceBase).

AgentAccessTokenValidationRequest

Request payload for token validation.

Property Type Description
AccessToken string The full token string to validate.

AgentAccessTokenValidationResult

Result of a token validation operation.

Property Type Description
Valid bool Whether the token passed all validation checks.
VirtualIdentity UnifiedUserIdentity? The virtual identity associated with the token, populated only when Valid is true.

AgentClientSecretKey

Extends ClientSecretKey with agent-specific context parsing.

Property Type Description
InstanceId string The FoundationaLLM instance identifier.
ContextId string The encoded agent resource path.
Id string The unique token identifier.
ClientSecret string The cryptographic secret for validation.
AgentName string The agent name, extracted from the ContextId.

Summary of Key Design Patterns

Pattern Implementation
Secret-key authentication Tokens use a keya...ayek-delimited format with Base58-encoded components and a cryptographic secret, validated server-side against stored keys.
Virtual identity mapping Validated tokens are mapped to full UnifiedUserIdentity objects with synthetic UPNs, making them compatible with the entire request pipeline.
Group-based authorization Virtual Security Groups allow administrators to apply RBAC policies uniformly to all token holders for an agent, without managing individual token permissions.
One-time secret display Token secrets are shown only at creation time, following the same security pattern used by API keys in cloud platforms.
Hierarchical context encoding The ContextId encodes instance, resource provider, resource type, and agent name, ensuring tokens are intrinsically scoped to a single agent in a single deployment.
Dual authentication scheme The platform supports both Entra ID and AAT authentication schemes simultaneously, with the AgentAccessTokenAuthenticationHandler operating alongside standard JWT validation.