One leaked secret. Forty agents. That’s the math: a single client_credentials grant, one secret in a vault (or, let’s be honest, an environment variable), shared across every bot that needs to call your API. When the reconciliation agent gets popped, so does the one that moves money. You can’t revoke one without killing them all. You can’t tell them apart in an audit log. They are, as far as your authorization server is concerned, the same thing wearing forty hats.
We’ve done this dance before. Service accounts were the shared-household-password of machine identity, and we spent a decade learning to hate them. Now agents arrive, and the reflex is to reach for the same broken pattern at ten times the volume. Auth0’s announcement this week — expanding Client ID Metadata Document (CIMD) support to cover both manual pre-registration and dynamic registration, paired with Application Profiles — is the industry quietly admitting the shared-secret model doesn’t survive contact with agent sprawl.
CIMD isn’t an Auth0 invention. It’s the IETF OAuth working group’s draft-ietf-oauth-client-id-metadata-document, and the core idea is almost rude in its simplicity: the client_id is an HTTPS URL, and that URL points to a JSON document describing the client. No registration round-trip, no secret handed out of band. The authorization server dereferences the URL, reads the metadata, and now it knows who’s calling.
Here’s the order I’d actually roll it out, and where the sharp edges are.
1. Stop pretending agents are users — or service accounts
An agent is a client. Not a user with a weird name, not a service account you’ll “clean up later.” The first real decision is admitting that each agent instance deserves its own identity, its own scopes, and its own revocation story. If you skip this and keep issuing one fat credential, nothing below matters — you’ll have CIMD-shaped plumbing feeding the same shared-secret swamp. The entire point is per-agent identity. Act like it from line one.
2. Understand what the metadata document actually contains
Before you decide how agents register, look at what they’re registering. A CIMD is just RFC 7591-style client metadata, served at a dereferenceable URL. The critical rule: the client_id value must equal the URL the document lives at. That self-reference is what stops an agent from claiming to be someone else’s client.
Note what’s missing: no client_secret. Authentication rides on private_key_jwt and a jwks_uri, so there’s no shared secret to leak in the first place. If your agents are still presenting a static secret, you’ve recreated the problem with extra steps.
3. Pick a registration mode per trust tier, not per platform
This is the actual decision Auth0 just opened up, and the announcement’s framing — “now you can do both!” — buries the lede. The two modes are not equivalent, and dynamic is not the default.
Manual pre-registration means an admin vets and allowlists each agent’s CIMD URL before it can get a token. The agent still self-describes, but you hold the gate. This should be your default for anything you build, anything a vendor you have a contract with builds, anything that touches money or PII. Boring. Auditable. Correct.
Dynamic registration means the agent shows up with its CIMD URL and the authorization server fetches and onboards it on the fly. This is what you want for an agent marketplace or genuinely third-party agents you can’t enumerate ahead of time. It is also where people are going to hurt themselves.
4. Build your Application Profiles before you onboard a single agent
Application Profiles are policy templates — allowed grant types, token lifetimes, permitted scopes, auth methods — that you attach to agent clients at scale instead of hand-configuring each one. Treat them as the thing that makes dynamic registration survivable. Without a profile, a dynamically registered agent inherits whatever your defaults are, and defaults are how breaches happen.
Write at least two profiles up front: a tight one for third-party/marketplace agents (short-lived tokens, read-only scopes, no refresh tokens, private_key_jwt required) and a looser one for first-party agents you’ve vetted. The profile is where “self-registration” stops being a euphemism for “unregulated.” Anyone who calls dynamic registration “zero trust” without pointing at a profile like this is selling you the T-shirt, not the architecture.
5. Gate dynamic registration — fetching a URL is not vetting
Here’s what the cheerful version leaves out: when the authorization server dereferences an attacker-controlled client_id URL, you’ve just built an SSRF primitive and a denial-of-service lever if you’re not careful. Dynamic registration must sit behind controls — a domain allowlist, a required software statement, mandatory binding to a restrictive Application Profile, and rate limits on the fetch. The metadata document being signed or served over authenticated TLS is the difference between “discoverable” and “forgeable.” Decide which URLs you’ll even dereference before you turn this on.
6. Scope every agent down to what it does, and set token lifetimes you’d defend in an incident review
Per-agent identity is worthless if every agent asks for and gets *. The reconciliation agent reads invoices; it does not need payments:write. Push scope constraints into the Application Profile so they’re enforced centrally, not negotiated per request. And keep agent access tokens short — minutes, not hours. Agents call constantly; they can afford to refresh. The blast radius of a stolen token should expire while the attacker is still reading the docs.
7. Make revocation a per-agent operation and test it
The single biggest win over shared service accounts is this: you can kill one agent without killing the fleet. But only if you’ve kept identities distinct and your profiles don’t quietly let a revoked agent re-register itself thirty seconds later. Actually run the drill. Revoke one agent, confirm its tokens die, confirm it can’t silently re-onboard through dynamic registration, confirm the other thirty-nine keep working. If you’ve never tested revocation, you don’t have revocation.
8. Implement CIMD in the agent, not just the server
For developers building the agents: host a stable, dereferenceable metadata document at a URL you control, keep client_id equal to that URL, publish a jwks_uri, and rotate keys there instead of distributing secrets. If you’re shipping an agent others will run, a clean CIMD is now part of your integration story the way a well-formed OpenAPI spec is. Agents that can’t self-describe are going to feel as dated as an app that still wants your password instead of an OAuth handshake.
9. Mind the maturity — this is a draft and a young feature
The honest caveat: CIMD is an active IETF draft, not a ratified RFC, and field names and rules can still shift. Auth0’s support is new. Check the current preview/GA status and tenant availability for your plan before you bet a production rollout on it, and pin to the draft version you tested against. The pattern is right. The spec is still wet paint. Those are different statements, and good architecture respects both.
If you do only one thing this quarter: stop issuing a shared credential to your agents and give each one an identity you can scope and revoke on its own. CIMD and Application Profiles are the cleanest way to do that at scale right now — but the lesson underneath is the one we keep relearning. Shared secrets don’t scale, they just fail quietly until they fail loudly. Agents are about to prove it again, faster than service accounts ever did.
