Anyone Who Copies the Secret Is the Agent
The agent now has an identity. What proves it is a credential, and a credential sitting in a configuration file or baked into a container image is a credential somebody else can hold. A token lifted off the wire has the same problem: whoever presents it looks exactly like the agent that earned it.
ThunderID answers this three ways, and they stack. You can replace the secret when it leaks, avoid having a shared secret at all, or make a stolen token worthless to the thief.
Prove the Agent's Identity
An agent authenticates to the token endpoint before it receives anything, with either a client secret or a signed assertion, and the choice is a property of the agent. That authentication applies whichever grant it uses. To get a token as itself rather than for a person, it then uses the client credentials grant.
Agents are confidential clients by default, meaning they hold a credential of their own. An agent can be registered as a public client instead, but a public client cannot prove its own identity, so it cannot use the client credentials grant and can only act in flows a user drives. Any agent that acts on its own therefore holds a credential.
See Agent Authentication for both mechanisms and Client Authentication Methods for how the agent presents each one.
Rotate the Client Secret
A client secret is issued when the agent gets its OAuth configuration, and it can be replaced whenever you need, either on a schedule you keep or straight after a suspected leak. Regenerating shows the new secret once and stops the old one working immediately, so deploy the new value as part of the same change.
Rotating touches the credential and nothing else. The agent keeps its identifier, its roles, and everything it has been granted, which means a rotation is not an authorization change and never needs to be treated as one.
See Use a client secret for the Console action, and for the read-modify-write that replaces it through the API.
Remove the Shared Secret
An agent that should not hold a shared secret at all authenticates with private_key_jwt instead, proving
itself with a signed JSON Web Token (JWT) rather than a shared string. It signs
an assertion with a private key only it possesses, and ThunderID verifies that signature against the
public keys you register. Nothing secret sits in your configuration for anyone to copy.
The keys are registered as a JWKS, which is a key set rather than a single key. That is what makes an unhurried rotation possible: publish the new key alongside the current one, move the agent over, then retire the old key, with no window where the agent cannot authenticate.
See Use a private key JWT and JWKS for the certificate formats.
Bind the Token to the Agent
Rotation and signed assertions both protect the credential. Neither helps once a token has been issued and copied, because a bearer token works for whoever presents it.
DPoP (RFC 9449) closes that gap by binding the access token to a key the agent holds. Each request carries a fresh proof signed with that key, and a resource that receives the token without a matching proof rejects it. A token copied out of a log or intercepted in transit is then not usable on its own.
There is no setting to switch on. An agent opts in per request by sending a DPoP header when it asks for a
token, and ThunderID binds the token it issues in response.
The binding is visible in the token. ThunderID embeds a thumbprint of the agent's public key as the
cnf.jkt claim, and the token comes back with a type of DPoP rather than Bearer:
{
"sub": "agent-identity-concierge",
"cnf": {
"jkt": "0ZcOCORZNYy-DWpqq30jZyJGHTN0d2HglBV3uiguA4I"
},
"iss": "https://localhost:8090",
"aud": "https://api.travel.example/booking",
"scope": "booking:read booking:recommend",
"client_id": "agent-identity-concierge-id"
}
A resource server computes the thumbprint of the key in the proof it received and compares it to cnf.jkt. If
they do not match, the request is refused, however valid the token itself looks.
See DPoP: Sender-Constrained Tokens for the proof claims and what a resource server validates.