Skip to Content
MCP GatewayMCP Server Authentication

User identity assertion

Send a signed token naming the person behind each call, so your MCP server can trust who's calling without a login

An internal MCP server often needs to know the person behind a tool call, to scope results to what they may see or to log who did what. With user identity assertion, the gateway sends a signed token naming that person on every call, in the X-SecureAuth-Jwt-Assertion header. Your server verifies the signature and reads the person from the token, with no separate login and no trust in the network.

How it works

  1. A person's agent calls a tool on your custom server through the gateway.
  2. The gateway has already authenticated the agent and the person it acts for.
  3. It signs a short-lived token with that person's ID, email, name and groups, and adds it to the request.
  4. Your server checks the signature against your workspace's public keys, then reads the person from the claims.

The token proves the gateway vouched for the person, so a request that didn't come through the gateway can't carry a valid one.

Turn it on

  1. Open the custom server from Inventory › Tools & Services, then its Settings tab.
  2. Under User identity, switch on Send user identity.
  3. Save, then copy the Issuer, JWKS URL and Audience shown there into your server's verification settings.

Only custom servers support it, and the gateway requires an https server URL.

User identity section on a custom server's Settings tab: Send user identity switched on, the signed token with its header, issuer, JSON Web Key Set (JWKS) URL and audience, and plain headers switched on below a warning that they aren't signed
The signed token comes first; plain headers are an opt-in with a warning

When the gateway sends it

The gateway sends identity only when a person calls through an agent and has an email address on file. Autonomous agents send none. The background tools sync and the connection check when you add the server also send none, because no person is calling. If your server demands the identity on every call, let it answer tools/list without it.

What the token carries

The token is a JSON Web Token (JWT) signed with ES256 (Elliptic Curve Digital Signature Algorithm with P-256 and SHA-256). It lasts 5 minutes, and the gateway issues a new one before it expires. It carries these claims:

ClaimValue
issYour workspace URL, shown as Issuer
audYour server URL without its query string, shown as Audience
subThe user's ID
emailThe user's email address
nameThe user's display name
groupsThe user's group names, as an array (empty when the user has none)
iat, expWhen the gateway issued the token, and when it expires

Verify the token

Your server fetches the public keys from the JWKS URL (JSON Web Key Set), which is /.well-known/identity-assertion/jwks.json on your workspace URL. Pin all of the following, so a token issued for another workspace or another server fails:

  • the issuer
  • the JWKS URL
  • the audience
  • the ES256 algorithm

In Node, use jose:

import { createRemoteJWKSet, jwtVerify } from "jose";

const jwks = createRemoteJWKSet(new URL(JWKS_URL));

const { payload } = await jwtVerify(
  request.headers["x-secureauth-jwt-assertion"],
  jwks,
  { issuer: ISSUER, audience: AUDIENCE, algorithms: ["ES256"] },
);

In Go, use go-oidc:

keySet := oidc.NewRemoteKeySet(ctx, jwksURL)
verifier := oidc.NewVerifier(issuer, keySet, &oidc.Config{
	ClientID:             audience,
	SupportedSigningAlgs: []string{oidc.ES256},
})

idToken, err := verifier.Verify(ctx, r.Header.Get("X-SecureAuth-Jwt-Assertion"))

Token size limit

A person in many groups can push the token past its size limit. Then the gateway leaves out groups and sets "groups_truncated": true. Look the groups up yourself when you see that claim, rather than treating the person as having none.

Next steps

Your server can now trust which person each call is for, and scope or log by it. Next, decide whether it also needs the same identity as plain headers.

On this page