Skip to content

Principal and Application

A principal is the identity that acts in Caracal. At token-exchange time, the principal is always an application — a registered client that presents credentials to the STS to obtain a mandate. This page explains how applications are structured, how they authenticate, and how the principal appears in policy input.

An application is a Caracal-registered client within a zone. It represents a service, agent process, automation script, or any other system that exchanges credentials for mandates. Applications belong to exactly one zone.

Applications are stored in the applications table with these attributes:

FieldDescription
idUUID; the application_id carried in mandates as client_id
zone_idThe zone this application belongs to
nameHuman-readable label
registration_method"managed" (created via API) or "dcr" (Dynamic Client Registration)
credential_typeHow the application authenticates; see below
traitsOptional string tags used in policy decisions
consentWhether user consent is required for this application

The credential_type field determines how the STS authenticates the application at token exchange:

TypeDescription
tokenBearer token exchanged for a mandate — the default for machine clients
passwordClient ID + secret (OAuth 2.0 client credentials)
public-keyAsymmetric key assertion
urlCallback URL-based assertion
publicNo client authentication — for public clients

For most agent workloads, token or password are the appropriate choices.

At token exchange (POST /oauth/2/token), the application presents its credentials in one of:

  • client_secret form field — symmetric secret stored as a hash in the database
  • client_assertion form field — signed assertion for public-key clients

The STS looks up the application by application_id and zone_id, verifies the credential, and then proceeds to OPA evaluation. No mandate is issued before the application credential is validated.

When the STS runs an OPA evaluation, the input.principal object represents the authenticated application:

{
"principal": {
"type": "application",
"id": "app-uuid",
"zone_id": "zone-uuid",
"credential_type": "token",
"agent_session_id": "session-uuid"
}
}

Policies can gate on any of these fields. The id is the application UUID; use it when writing policies that restrict access to specific applications. The agent_session_id links to the agent session in the Coordinator, useful for policies that gate on session state.

Applications have an optional traits string array. Traits are arbitrary labels — for example, ["trusted-internal", "finance-team"] — that the application carries into the OPA input via actor_claims. Policies can inspect traits to grant broader access to specific application categories without hardcoding UUIDs.

Caracal does not include a built-in user directory. A user_id is an opaque string passed by the calling application; Caracal stores it in the grant but does not validate it against any identity provider.

A grant binds a (application_id, user_id, resource_id) triple to a set of scopes, representing that the specified application is authorized to access the resource on behalf of the specified user. Grants are the connection point between an application and a resource — without a grant, the application has no access to the resource regardless of policy.

In a typical agent workflow, the user_id in a grant represents the end user who delegated the agent to act on their behalf. The agent application holds the grant; the user identity is carried for audit and policy purposes.

If the zone has dcr_enabled = true, applications can be registered dynamically via RFC 7591 Dynamic Client Registration. DCR-registered applications go through the same OPA evaluation as managed applications.

The principal in Caracal always identifies an application at the time of token exchange, not a human user. Human users are represented indirectly through grants that bind a user_id to an application’s access rights. The human’s identity is present in the OPA context via actor_claims if a user session token is carried, but the principal type is still "application".

  • Zone — the tenancy boundary each application belongs to
  • Resource and Grant — how grants bind applications to resource access
  • Policy — using input.principal in policy rules