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:
- The administrator specifies a description and an optional expiration date.
- The platform generates a unique
Id(GUID) and aClientSecret. - An
AgentAccessTokenresource is created withActive = true. - The token is stored via the authorization service using
UpsertSecretKey. - 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:
- Format validation — The token string is parsed to extract
InstanceId,ContextId,Id, andClientSecret. Invalid format results in immediate rejection. - Token lookup — The system loads all tokens for the agent identified in the
ContextIdand verifies that a token with the matchingIdexists. - Expiration check — If the token has an
ExpirationDate, it is compared against the current UTC time. - Active check — The token's
Activeflag must betrue. - Agent match — The agent name extracted from the token must match the agent associated with the loaded tokens.
- Cryptographic validation — The
ClientSecretis 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:
- Copy the agent's Virtual Security Group ID from the agent configuration.
- Navigate to the agent's Access Control page.
- 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
- Scope:
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. |