Connecting an Agent Directly
An agent can fetch a Connection token straight from the vault, with no Resource in between.
This page wires that up with the Agent Auth SDK, using a support agent as the example: your app already logs the user in, the backend agent receives that user's JWT, and exchanges it for a Connection token to act on the user's behalf.
Note
Direct access works, but generally it is better to have a Resource between the agent and the vault: the agent holds a short-lived Descope token that the Resource validates, and the exchange for Connection tokens happens inside the Resource, so provider credentials never reach the agent.
For agentic use cases that Resource is most commonly an MCP server, but it can be a plain API. See Keep credentials off the agent.
When direct access fits
- Your app already authenticates users and can hand the agent a user JWT.
- The agent runs in your own backend, in a trust boundary you control.
- You want the shortest path from "user asked the agent something" to "agent called HubSpot or Google on their behalf."
Per-user access is governed by the policy on the Connection, and every fetch is audited.
Why a Resource is Usually Better
Direct access hands the agent the provider credential itself, and those tokens and API keys are often long-lived. With a Resource in front:
- The agent authenticates to the Resource and holds only a short-lived Descope token, scoped by audience and Resource scopes.
- The Resource validates that token, then exchanges it for the Connection token inside its own trust boundary.
- The provider credential never leaves your server; the agent sees only tool results.
For agents this Resource is most commonly an MCP server, but any API you protect with Descope works the same way.
How to Wire Up Direct Access
Create the Connection
Create a Connection for the service the agent calls, for example HubSpot, with the scopes its tools need. The user links their account once through the connect flow, and Descope stores and refreshes the token.
Hand the agent the user's JWT
Your frontend already holds the user's Descope JWT from login. Pass it to the backend where the agent runs, the same way you pass it to any API you protect.
Exchange it for a Connection token
Bind the SDK client to the user's token and fetch. If the user has not linked the account yet, ConnectionAuthorizationRequired carries a connect URL to send them through.
from descope_agent_auth import AgentAuthClient, AccessTokenProvider
from descope_agent_auth.errors import ConnectionAuthorizationRequired
client = AgentAuthClient(
project_id="P2...",
credential=AccessTokenProvider(access_token=user_jwt), # the JWT from your app's login
)
try:
hubspot = client.connections.get_token(connection="hubspot", identifier=user_id)
create_ticket(hubspot.access_token) # a fresh, scoped HubSpot token
except ConnectionAuthorizationRequired as e:
redirect_user_to(e.connect_url) # the user hasn't linked HubSpot yetimport { AgentAuthClient, AccessTokenProvider, ConnectionAuthorizationRequired } from '@descope/agent-auth';
const client = new AgentAuthClient({
projectId: 'P2...',
credential: new AccessTokenProvider({ accessToken: userJwt }), // the JWT from your app's login
});
try {
const hubspot = await client.connections.getToken({ connection: 'hubspot', identifier: userId });
createTicket(hubspot.accessToken); // a fresh, scoped HubSpot token
} catch (e) {
if (e instanceof ConnectionAuthorizationRequired) {
redirectUserTo(e.connectUrl); // the user hasn't linked HubSpot yet
} else {
throw e;
}
}Call the provider
The token is scoped to what the Connection and its policy allow. Call the provider's API with it; Descope handles refresh, so ask for a token whenever a tool runs rather than caching one long-term.