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:

  1. The agent authenticates to the Resource and holds only a short-lived Descope token, scoped by audience and Resource scopes.
  2. The Resource validates that token, then exchanges it for the Connection token inside its own trust boundary.
  3. 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 yet
import { 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.

Was this helpful?

On this page