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 |
Where is it passed? | — | HTTP header |
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 |
|
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 |
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:
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.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.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
Element | Value | Rule |
|---|---|---|
|
| Identifies your application, not the user |
| Compact JWS (JWT) | Identifies the user. The only place a user is ever passed. |
| Your share ID | Must be a delegated share bound to this gateway key |
| Origin of the page that shows the chat | Must be one of the share's allowed origins |
| Value received from the browser component | 16–128 characters |
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 |
|---|---|---|
| Yes |
|
| Yes | Key ID present in your JWKS |
| No |
|
Claims
Claim | Required | Rule |
|---|---|---|
| Yes | Exactly the issuer registered for your tenant (case-sensitive, no trailing-slash tolerance) |
| Yes | The audience registered for your issuer (e.g. |
| Yes | The user. Stable, unique, opaque ID of the user within your issuer — see below |
| Yes | Expiry. Use ≤ 5 minutes after issue; Ragty allows 60 s clock skew |
| Recommended | Issue time; validated if present |
| 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)
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 | Use different formats in chat and ingestion ( |
Keep it opaque (no personal data needed) | Put names or other personal data into |
Use exactly one value per person | Reuse a |
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 rawsubis never stored or logged and never returned.The same
iss+subalways 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
subare 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 |
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 theX-End-User-Assertionheader of your backend's ticket request. Everything else (history, documents, isolation) follows fromiss+sub.