Agent authentication Module

Vaks PM · Integration guide · Agent authentication · July 2026

What this covers. How an activated agent obtains the short-lived token it uses on every API call — without you distributing a long-lived secret. This is the step after an agent exists in Vaks PM. If your agents are not created yet, start with Agent directories; this guide assumes an agent already exists, owned by a human, with a trust level and capabilities set.

Three ways an agent gets a token

Every agent action is authenticated by a short vaks_pat_ token that carries the agent's identity. There are three ways to obtain one, and they differ only in where the trust comes from:

MethodTrust anchorBest for
Manual token A human issues a token in the admin and hands it to the agent. A handful of agents; anything without an identity platform. Covered in Agent directories → Activate.
Federation this guide The agent's execution platform signs a token proving its identity; Vaks PM verifies it and exchanges it. No secret is ever distributed. Agents running on a platform that issues workload identities: Kubernetes, Microsoft Entra (Copilot Studio, Azure AI Foundry), GitHub Actions.
Headless self-service this guide The agent holds a rotating refresh credential and renews short tokens itself. Agents with no identity platform: a self-hosted runtime, a script, a bespoke orchestrator.
These are a licensed capability. Federation and headless self-service both require the agent-federation feature on your licence. The manual token path always works and is never a prerequisite — federation is the convenience that removes secret handling at scale, not a gate on running agents.

Which one to use

The deciding question is simple: does the platform running the agent hand it a signed identity token?

Agent authentication is not user delegation. Both paths here produce an agent token — the agent acts as itself, with its own capabilities, its human owner attached for accountability. This is a different surface from the browser sign-in used by the AI connector (MCP), where the AI borrows a signed-in user's rights. The two never share a credential or a session, and are served on different parts of the platform.

Federation — what to configure in Vaks PM

Federation follows the OAuth 2.0 token-exchange standard (RFC 8693). You declare which issuer you trust; the agent then presents a token from that issuer and receives a short Vaks PM token in return.

Open Admin → Integrations → Federated agent identity and press Add issuer. The fields:

FieldWhat to put
LabelFree text, shown in the list.
IssuerThe exact iss claim the platform puts in its tokens, character for character. For Entra: https://login.microsoftonline.com/<tenant-id>/v2.0.
AudienceThe value the platform will place in the token's aud claim, e.g. api://vaks-pm/<your-slug>. Mandatory — it is the single control that stops a token the agent obtained for another service (say Microsoft Graph) from being accepted here. Whatever you choose, configure the same string on the platform side.
Identity sourceMust match the agent's own source: entra-agent for agents imported from Entra, api for agents registered inbound, or a value of your own for a self-declared issuer such as k8s. An agent can only be authenticated by an issuer whose identity source matches its provenance — a defence-in-depth check.
Signing keysOne of three: an OIDC discovery URL (Vaks PM resolves the key set for you), a JWKS URI, or a pasted JWKS. Paste the key set when the issuer is internal or air-gapped — verification then makes no outbound call at all.
Subject claimThe claim holding the agent's identifier, default sub. This must equal the agent's stored external ID. Entra workload tokens sometimes carry it in oid instead — this is the field to adjust if a valid token is rejected as an unknown agent.
Token TTLLifetime of the issued token, 300–3600 seconds.
Claim constraints (optional)Extra claims required for an exact match, e.g. { "repository": "org/repo" } to accept only one GitHub repository.
Enable this issuerUntil ticked, every exchange is refused.

Press Test to confirm the key set is reachable. Then make sure the agent that will authenticate has its external ID set to the value the platform puts in the subject claim — that is the link between the signed token and the Vaks PM identity.

Deriving from an Entra directory connector. If you already run an agent directory against the same Entra tenant, the issuer form can pre-fill the issuer, audience and identity source from it in one click. The values are a snapshot, not a live link: changing the connector afterwards does not move the issuer, and the screen warns you if the two drift apart.

Once an issuer is declared and the agent is activated, the agent authenticates like this — the platform provides the JWT, the agent only forwards it:

POST /api/v1/auth/oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=urn:ietf:params:oauth:grant-type:token-exchange
&subject_token=<the platform-issued JWT>
&subject_token_type=urn:ietf:params:oauth:token-type:jwt

→ { "access_token": "vaks_pat_…", "expires_in": 3600, "scope": "…" }

The returned token is an ordinary agent token, bounded by the agent's capabilities. When it expires the agent simply exchanges again — there is no refresh token to manage, because the platform re-issues the source JWT on demand.

Platform recipes

The Vaks PM side is identical everywhere — the issuer declaration above. What changes is how the platform is told to issue a token for your audience. We do not reproduce each platform's own documentation here; the links go straight to the authoritative source. In every case, the value you set as Audience in Vaks PM must be the same value the platform is configured to request.

Kubernetes & generic OIDC issuers

The simplest case, and the cleanest for an on-premises deployment. A pod requests a projected ServiceAccount token with your audience; the kubelet writes it to a file and rotates it. In Vaks PM, set the issuer to your cluster's OIDC issuer and either point the JWKS URI at it or paste the cluster's key set for a fully air-gapped setup.

Microsoft Copilot Studio

A Copilot Studio agent can act as itself once you enable Entra Agent ID for the environment: it receives an Entra service principal and authenticates secret-less using federated identity credentials. Configure its call to Vaks PM with your audience, and declare the Entra tenant as the issuer here.

Mind the two modes. Copilot Studio's default connector mode is on-behalf-of, where the agent acts with the signed-in user's permissions — that is user delegation, and belongs to the MCP surface, not here. Federation applies only when the agent acts as its own Entra identity. (On-behalf-of, for reference.)

Azure AI Foundry

A Foundry agent is given a dedicated Entra identity through a managed identity and a federated credential; at runtime Foundry acquires a token for that identity scoped to a downstream audience you configure. Set that audience to your Vaks PM value, and declare the Entra tenant as the issuer here. This is the closest match to the token-exchange model — Foundry does most of the work before it even reaches Vaks PM.

GitHub Actions

A workflow with id-token: write can mint a short OIDC token per job for your audience. Use claim constraints in the issuer to pin it to a single repository or environment.

Supported by design, worth a dry run. The Entra-based recipes (Copilot Studio, Foundry) rest on one detail that depends on your tenant: that Entra will mint a token whose aud equals your Vaks PM audience, and whose subject claim equals the external ID stored on the agent. Both are configurable here precisely so you can line them up, but confirm the first successful exchange against your real tenant before relying on it in production.

Headless self-service — machine credentials

When there is no platform to sign a token — a self-hosted agent, a script, a bespoke runtime — the agent instead holds a durable, rotating refresh credential and renews short working tokens on its own. A human issues it once; after that no human is in the loop.

Open Admin → Users & Identity → Agents, select the agent, and under Machine credentials press Issue credential. The secret (vaks_agr_…) is shown exactly once — hand it to the agent's own configuration store. The agent then loops:

POST /api/v1/agents/token
Content-Type: application/x-www-form-urlencoded

grant_type=refresh_token
&refresh_token=vaks_agr_…

→ { "access_token": "vaks_pat_…",   // ~1 h, use on every call
       "refresh_token": "vaks_agr_…",  // NEW — store it, the old one is now spent
       "expires_in": 3600 }

Two properties make this safe to leave running unattended:

Revoking the credential (same screen) cuts the agent off immediately — it would need a human to issue a new one. Suspending the agent, or its human owner, has the same effect on the next call.

This is not the MCP browser flow. Machine credentials are served on a dedicated endpoint that never involves a browser, a consent screen, or a user session. It issues agent tokens only. The user-facing AI connector (MCP) remains entirely separate.

External agents & their exposure limit

An agent hosted on an external platform (Copilot Studio, Azure AI Foundry, a cloud runtime) has to reach Vaks PM over the network. In an on-premises deployment you do not expose the internal API to the internet: a minimal, secret-less relay in a DMZ is the single public door, and it forwards only a curated surface to the internal API. The internal API, database, cache and object store are never directly reachable.

That relay draws a deliberate network boundary around what an externally-hosted agent can reach in REST, on top of the per-request checks. A federated agent is bounded twice over:

LayerWhat it enforces
Capabilities (always)An agent's effective rights are its role's permissions intersected with its token's scopes intersected with its capabilities. Finance, client data, the user directory, timesheet and audit can never be granted to an agent, whatever route it reaches.
Network allow-list (hardened DMZ deployment)The relay forwards only the agent work surface — tasks, projects, deliverables, comments, attachments, skills, workload, allocations, time, agent runs, teams, holidays. The finance, clients, users, audit and reporting controllers are not forwarded at all, so they are not even reachable from the internet by this path.
The limit is on the direct-REST path only. This narrowing applies to an agent calling the REST API directly through the DMZ. It does not affect the AI connector (MCP): the MCP server reaches the internal API by its own outbound path, so a person using MCP tools keeps the full tool set (bounded, as always, by the MCP toggles and their own RBAC). The two surfaces are independent.

The capability ceiling is the authoritative, always-on boundary; the network allow-list is defence in depth for the hardened deployment. In the demo, where the whole app is internet-facing for convenience, only the capability ceiling applies — the network narrowing is a property of the DMZ relay, which ships as a deployment template (infra/dmz/) rather than being on by default.

What is logged

Everything here leaves an audit trail under Admin → Security & Compliance → Audit log, exportable to your SIEM:

ActionRecorded
Issuer created, updated, deletedActor and issuer, at critical severity. Declaring who may vouch for an agent is a root-of-trust decision.
Machine credential issued, revokedActor and target agent, at critical severity. A theft-triggered revocation is recorded with its reason.
Successful exchangeAt informational severity, attributed to actor type AGENT — a token is minted once per hour per agent, so these are frequent by design.
Refused exchangeAt warning severity, with the reason (unknown issuer, wrong audience, replay, inactive owner, and so on) — these are what you watch.

Related: agent directories to create the agents first · product & features for the agent governance model · AI connector (MCP) for user-delegated access · all integrations.