Nothing to configure on TrustGate
There is no per-tenant setup, no flag on the application and no gateway setting. TrustGate reads the headers below on every request; a request that declares nobody behaves exactly as it did before.Ways to declare the end user
TrustGate takes the first source that names somebody:
TrustGate’s own namespace comes first on purpose: if you set
X-TG-*, you did so
deliberately, so a request carrying both yours and a vendor’s is attributed the way you
asked. The body user field is a last resort — it is one opaque id, not a person — and is
read only when no header named anyone.
You do not have to send all four fields. Any one of id, email or name is enough; a header
set where every value is blank is skipped, and the next source is tried.
Clients TrustGate recognizes
Some clients already forward the signed-in user in their own headers. TrustGate reads those conventions as they are, so the client needs no change and TrustGate no setup:
A signed token from a client is read for its claims; its signature is not checked, because
the secret belongs to the client. It is recorded under the same rules as any other
declaration.
Your own client
Any client — a backend, a custom UI, a proxy — can attribute with TrustGate’s namespace:The OpenAI user field
A client that already sets the OpenAI API’s user field needs no headers at all:
Verified attribution with SSO
Everything above is declared by the client. To attribute traffic to a person the gateway has verified, the client sends each user’s own identity-provider token asAuthorization: Bearer, in place of a shared API key. TrustGate validates it — signature
against the IdP’s keys, issuer, expiry, audience, and the application’s allowed client ids
— and records the person it names as the request’s principal. Configuring the provider
is covered in Authentication.
This needs a client that signs users in with your IdP and can forward their token, and a
token issued for the audience TrustGate expects. Open WebUI
does both with its OAuth connection.
The principal is recorded as principal_subject (the token’s sub) and principal_email:
the token’s email claim or, when the IdP sends none, the first of emailAddress,
preferred_username, upn and unique_name that is an address. Unlike a declared user,
the principal reaches policies: guardrail rules that match on the user see this person.
A forged or expired token is rejected with 401; it never attributes anything.
Grouping a conversation
A chat client sends each message as its own request. Without a conversation id every message looks like a fresh session, which makes session-scoped alerts and any “conversation” view useless. TrustGate takes the first of these that carries a valid id. An id the client sent — a header or the configured body field — always wins over one the gateway infers:-
The session header configured on the gateway (
X-Session-Idby default) -
A header a known client already sends:
-
Any other header named
x-<vendor>-session-id - The body field named by the gateway’s session configuration, if set
-
On OpenAI Responses requests, the
conversationid (Conversations API) -
On OpenAI Responses requests, the conversation of the response named in
previous_response_id— so a chain of turns stays one conversation even when the client sends no id - A generated id
session_id and echoed back on the response as X-Session-Id.
The first three headers and the configured header and body field accept 1–256 characters.
The rest accept 8–256 characters of letters, digits and . _ : -: a header that only
shares a name, or a short placeholder, must not merge unrelated traffic into one session.
A generated id stands for a whole conversation only on OpenAI Responses, where it is the id
of the chain of turns. On every other API it is a single request: it is echoed so a client
can adopt it and send it back, but nothing records it as a session.
session_id contains an underscore, which ingress-nginx drops unless
enable-underscores-in-headers: "true" is set in its ConfigMap. Without it, Codex CLI
requests fall through to the next source.session.enabled: false, none of these
sources are read.
Where it shows up
Activity. The User column shows the declared person instead of the API key’s principal. Because the name is unverified it is marked as such, and opening a request shows who declared it and, beside it, the credential that authenticated — both facts at once. When the declared email is the verified principal’s — a client forwarding both the user’s IdP token and its own user headers — the user is shown as verified: the gateway vouched for that very person. Event stream. Two fields on the TrustGate event, both documented in the Event schema:
OpenTelemetry. Exported as
trustgate.end_user plus
trustgate.end_user.id, .email, .name, .role and .source.
Values are trimmed and capped at 256 characters. A declaration that names nobody — only a
role, say — records no identifier, so nothing groups under an empty user.
Not an identity
TrustGate distinguishes two different things, and so should any query you write over this data:
Anyone who can reach your gateway with a valid API key can put any name in these headers.
Use them to understand and bill traffic; do not use them to decide who may do what. If you
need a person TrustGate verifies, send their own IdP token — see
Verified attribution with SSO. For an end user whose
identity TrustGate acts on in MCP, that is a different mechanism — see
End users of your application for the MCP case, where each
person connects their own upstream accounts.
Related
- Event schema: the field contract alerts and analytics match on
- Applications: API keys, bindings, and the principal behind a request
- Authentication: trusting your identity provider and admitting its tokens
- Open WebUI: every way Open WebUI identifies its users, end to end