
Let agents act with a person’s permission
A person can authorize a connected tool to act through a particular agent endpoint without sharing a full application session. Wildo binds the token to that destination and retains both the person’s identity and the requesting client’s attribution.
The person’s current roles still determine which operations are available.
Example — Approve a tool for one assistant
A tool receives permission to call the selected MCP endpoint. That token does not become permission to call the ordinary application API or a different agent instance.
For engineers
The authorization request names the intended resource. The code exchange reads that stored audience and rejects a different resource echoed by the token request. It then verifies the audience against the registered delegatable endpoints:
This implementation excerpt from oauth-provider-token.backend.service.ts shows the decision in context; explanatory source comments are omitted.
const requestedAudience = grant.resource;
if (!requestedAudience) {
throw this._oauthError(ErrorType.AUTHORIZATION, ErrorCustomMessageReference.AUTHORIZATIONS_ACCESS_DENIED, 'invalid_target',
'the `resource` parameter (RFC 8707) is required for the authorization_code grant');
}
if (request.resource && request.resource !== requestedAudience) {
throw this._oauthError(ErrorType.AUTHORIZATION, ErrorCustomMessageReference.AUTHORIZATIONS_ACCESS_DENIED, 'invalid_target',
'the token-request `resource` does not match the resource authorized at the authorization endpoint');
}
const allowedDelegatedAudiences = this.container
.get<ResourceServerInstancesRegistryBackendService>(SAAS_SERVICE_TYPES.ResourceServerInstancesRegistry)
.listResourceServerAudiences(DELEGATED_TOKEN_RESOURCE_SERVERS);
if (!allowedDelegatedAudiences.includes(requestedAudience)) {
throw this._oauthError(ErrorType.AUTHORIZATION, ErrorCustomMessageReference.AUTHORIZATIONS_ACCESS_DENIED, 'invalid_target',
`resource '${requestedAudience}' is not a delegatable agent endpoint (A2A / MCP)`);
}
Keep identity and business permissions separate
The delegated access claim includes the user, their authorization version and azp, which identifies the authorizing client. Business roles are resolved at request time; granting an identity scope does not grant the ability to edit a record.
Before issuance the provider checks that the user remains active and has a usable authorization version. The delegated token lifetime is capped and no refresh token is returned. The connected tool must return through authorization when it needs a new delegation.
Call through the agent contract
Present the returned Bearer token to the audience it names and use that endpoint’s MCP or A2A contract. The resource server verifies the audience before dispatching the operation. This preserves a different boundary from a machine principal, whose roles belong to the registered service rather than a consenting user.
Carry the delegation into an MCP request
Use the complete discovery and PKCE recipe to obtain accessToken, expiresIn and the original resource. For an MCP delegation, that resource is the exact chosen MCP endpoint, including a named instance when applicable. It is not the application’s general API origin.
After the MCP handshake has negotiated the locally supported 2025-06-18 revision and sent the initialized notification, this illustrative request lists the tools available to the consenting person:
const response = await fetch(resource, {
method: 'POST',
headers: {
authorization: `Bearer ${accessToken}`,
'content-type': 'application/json',
accept: 'application/json',
'MCP-Protocol-Version': '2025-06-18',
},
body: JSON.stringify({ jsonrpc: '2.0', id: 2, method: 'tools/list', params: {} }),
});
if (!response.ok) throw new Error(`MCP HTTP ${response.status}`);
const envelope = await response.json();
if (envelope.error) throw new Error('MCP discovery was refused');
const tools = envelope.result.tools;
Select a tool and its argument schema from that authenticated result before calling it. Tool exposure and the person’s current business permissions still determine what can execute. An empty catalogue is not permission to invent a tool name. Other negotiated revisions require their own metadata, so let the client’s transport handle version changes.
| Outcome | Client response |
|---|---|
| Callback state or redirect mismatch | Reject the callback before attempting exchange |
| Different resource echoed at exchange | Correct the client request; the server cannot retarget the consented code |
| Token sent to another endpoint | Use the originally authorized resource; do not treat an audience refusal as a role problem |
| Expired delegation | Begin a new authorization; this grant does not return a refresh token |
| Authenticated operation refusal | Respect the user’s current scope/roles and the exposed operation contract |
For A2A, apply the same audience-bound Bearer to the selected A2A endpoint using its request and response contract. An agent token does not become a first-party API session merely because both endpoints belong to the same application.