Help Instance Help

How the User Is Passed

The most important integration decision is how Ragty learns who the user is. The answer differs strictly between the two access modes. This page is the binding reference for both.

Public share

Delegated share

Do you pass a user?

No. Never.

Yes — exactly one value: the sub claim of a signed JWT

Where is it passed?

—

HTTP header X-End-User-Assertion on POST /api/v1/embed/tickets, from your backend only

Who creates the identity?

Ragty (anonymous visitor per browser)

Your identity provider (signed end-user assertion)

What identifies the user?

A random visitor secret in an HttpOnly cookie

iss + sub of the verified assertion

What the browser ever sees

Share ID

Share ID and a one-time ticket — never the assertion, never the gateway key

Same history again when

Same browser on the same site

Same iss + sub, on any device

Public share: no user is passed

In a public share you do not and cannot pass a user. There is no attribute, URL parameter, header or API field for a user name, e-mail, customer number or session of your application — and none must be invented.

What happens instead:

  1. When the chat starts, the browser calls Ragty itself (POST /embed/v1/shares/{shareId}/visitor). You do not write this call; the web component or the iframe does it.

  2. Ragty creates an anonymous visitor and stores a random 256-bit secret in the cookie m8ty_v_<shareId> on the Ragty domain (HttpOnly; Secure; SameSite=None; Partitioned). Ragty keeps only a hash of it.

  3. On the next visit the browser sends this cookie automatically; Ragty recognizes the visitor, rotates the secret and shows the previous chats.

Consequences you must accept:

  • The "user" is the browser on your site, not a person. Two people sharing one browser share the history; one person with two devices has two histories.

  • The visitor is anonymous to you and to Ragty. You cannot look up a visitor's chats by your user ID, and Ragty cannot link them to your accounts.

  • Public chats only search documents that are not owned by a delegated user.

Delegated share: the user is passed as a signed assertion

In a delegated share your backend tells Ragty who the user is, by sending a short-lived JWT — the end-user assertion — that is signed by your identity provider. Ragty verifies it and derives the user from iss + sub.

The exact transport

POST /api/v1/embed/tickets HTTP/1.1 Host: rag.example.com Authorization: Bearer ragty-<gateway key> X-End-User-Assertion: eyJhbGciOiJSUzI1NiIsImtpZCI6Ii4uLiJ9.eyJpc3MiOiJodHRwczovL2... Content-Type: application/json {"share_id": "shr_XXXXXXXXXXXXXXXXXXXXXXXX", "origin": "https://portal.example.com", "nonce": "3f9c2b..."}

Element

Value

Rule

Authorization

Bearer + gateway key

Identifies your application, not the user

X-End-User-Assertion

Compact JWS (JWT)

Identifies the user. The only place a user is ever passed.

share_id

Your share ID

Must be a delegated share bound to this gateway key

origin

Origin of the page that shows the chat

Must be one of the share's allowed origins

nonce

Value received from the browser component

16–128 characters [A-Za-z0-9_-]; binds the ticket to that component instance

The assertion is never accepted in the request body, in a query parameter, from the browser or by the chat API (/embed/v1). The response is a ticket: {"ticket": "…", "expires_in": 60}. Only the ticket goes to the browser.

The exact assertion format

JOSE header

Field

Required

Value

alg

Yes

RS256 (or another asymmetric algorithm configured for your issuer)

kid

Yes

Key ID present in your JWKS

typ

No

JWT

Claims

Claim

Required

Rule

iss

Yes

Exactly the issuer registered for your tenant (case-sensitive, no trailing-slash tolerance)

aud

Yes

The audience registered for your issuer (e.g. ragty-chat)

sub

Yes

The user. Stable, unique, opaque ID of the user within your issuer — see below

exp

Yes

Expiry. Use ≤ 5 minutes after issue; Ragty allows 60 s clock skew

iat

Recommended

Issue time; validated if present

nbf

Optional

Validated if present

anything else

Ignored

Names, e-mail, roles are not used and should be omitted

Size limit: the whole assertion must not exceed 16 KB.

Example (decoded)

{ "header": { "alg": "RS256", "kid": "2026-11-portal", "typ": "JWT" }, "payload": { "iss": "https://idp.example.com/realms/customers", "aud": "ragty-chat", "sub": "CUST-0004711", "iat": 1794470400, "exp": 1794470700 } }

Choosing sub correctly

sub is the user for Ragty. Get it right before go-live — changing it later means users lose their history and their document access.

Do

Don't

Use an immutable internal ID (customer number, IdP user ID/UUID)

Use e-mail addresses, user names or phone numbers that can change

Use the same value that your document ingestion uses as subject for this user

Use different formats in chat and ingestion (4711 vs CUST-0004711)

Keep it opaque (no personal data needed)

Put names or other personal data into sub

Use exactly one value per person

Reuse a sub for a different person

Rules enforced by Ragty: not empty or whitespace only, no control characters, at most 512 bytes UTF-8, case-sensitive and never normalized (Cust-1 and cust-1 are two different users).

How Ragty uses it:

  • Ragty computes sha256(issuer_id + separator + sub) and stores only this key. The raw sub is never stored or logged and never returned.

  • The same iss + sub always maps to the same user: same chat history on every device, same owned documents.

  • Documents ingested for a user (delegated document ingestion, see Delegated End-User Isolation) are visible in the chat only if they were ingested with the same issuer and the same subject value.

  • If the user was erased in Ragty (GDPR erasure), tickets for this sub are refused until an administrator reactivates the user.

Where the assertion comes from

Use whichever your identity provider supports — the result must be a JWT with the format above, signed with a key published in the JWKS registered in Ragty.

Source

How

OIDC token exchange (RFC 8693), e.g. Keycloak

Exchange the user's session token for a token with aud=ragty-chat and a short lifetime

Client-credentials + impersonation in your IdP

Request a token for the user with the Ragty audience

Own signing service

Sign the assertion yourself with an RSA key; publish the public key as JWKS over HTTPS (see the example in Mint the assertion yourself)

Summary

  • Public: pass nothing. The browser is the user.

  • Delegated: pass exactly one thing — a signed JWT with sub = your immutable user ID — in the X-End-User-Assertion header of your backend's ticket request. Everything else (history, documents, isolation) follows from iss + sub.

12 November 2026