Connect agents and services
You've launched a protected application. Right now that means every call is denied — nothing holds a token yet. This section onboards the things that will call it, each with its own identity, its own grant, and its own kill switch.
Before you start
- A launched application — the full walkthrough is Protect an application
- Roles with scopes granted on that application (Access policy) — every caller below is admitted by assigning it one of those roles
Three kinds of callers
The first question is always the same: whose permissions apply when the tool runs?
| The caller… | Identity type | Example | Guide |
|---|---|---|---|
| acts as the signed-in user, interactively | OAuth client (DCR) | Claude Desktop, Claude Code, Cursor | Clients and connections |
| acts as itself, with standing permissions | Service account (M2M) | nightly pipeline, CI job, backend service, K8s workload | pick a credential below |
| acts on behalf of a signed-in user, unattended | Agent (ID-JAG delegation) | copilot, chatbot, research assistant | ID-JAG agents |
The first kind needs no onboarding from you: the client software registers itself via DCR the moment a user connects it to your server; the user logs in, consents, and every token carries that user's permissions. You just watch (and occasionally approve) from the Clients and connections page.
This section is about the other two — the callers that run unattended, and therefore need an identity you deliberately create and grant.
The shared model
Every caller this section covers goes through the same four stations:
- Identity — register it once: a Service Account, a workload, or an Agent.
- Grant — assign it a role on your application (Access tab). An
identity with no grant gets
access_deniedon every token request. - Token — the caller trades its credential for a short-lived access token scoped to your application.
- Connection — the live link shows up on the application's Connections tab: who, through which role, which scopes, last seen — and revocable per row.
M2M: pick your credential
Three ways a machine can prove who it is — same token flow, increasing security:
| Method | Proof | Secret stored? | Best for | Guide |
|---|---|---|---|---|
| A. Client secret | ID + shared secret | ⚠️ yes, on the caller | quick starts, simple deployments | Client secret |
| B. Private-key JWT | signed assertion (RFC 7523) | 🔑 private key only, never on the wire | enterprise security postures | Private-key JWT |
| C. Kubernetes / SPIFFE | platform-attested workload identity | ✅ nothing stored at all | Kubernetes clusters | Kubernetes / SPIFFE |
The ladder A → B → C goes from "shared password" to "asymmetric keys" to "the infrastructure itself vouches for the pod". Start where your deployment is; upgrading later doesn't change the grant model.
Agents: acting for a user
When a copilot answers Alice's request, the MCP server should apply Alice's permissions and the audit log should say "Alice, via agent X". That's ID-JAG delegation: the user consents once, an admin approves once, either side can revoke at any time.
Watching it all
- Application → Connections tab — pending requests and active connections for this server
- Sidebar → MONITOR → M2M Logs — every machine token grant as it happens
- Application → Access tab → Who has access — every identity, its role, its effective scopes, revocable per row