> ## Documentation Index
> Fetch the complete documentation index at: https://docs.gethinto.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Native Support security and identity

> Token signing, origin checks, customer isolation, and data visibility.

## Keys and tokens

Your organization has one Signal app. Every website and mobile app uses its publishable key and a short-lived JWT, which your backend signs or your sign-in provider issues. Hinto resolves the organization and the Signal app from the publishable key, and in a browser it answers that lookup only on a website from the list in Settings > Hinto Signal. A mobile app sends no origin.

The backend values (`HINTO_SIGNAL_APP_ID`, `HINTO_SIGNAL_KID`, and the signing secret `HINTO_SIGNAL_SECRET`) stay on your authenticated backend. Hinto shows the signing secret only when the app is created (by **Set up without a coding agent** in Settings > Hinto Signal, by the first `provision_hinto_signal` call, or by the pairing claim that creates the app), after **Roll secret**, or after a `provision_hinto_signal` call with `reissueCredentials`. Copy it to protected server configuration before closing the reveal. Ordinary settings reads never return it. If the value is lost, choose **Roll secret**. Tokens signed with the old secret are accepted only during the retiring window of 12 hours plus 60 seconds.

The publishable key is public by design. **Roll key** replaces it, and the old key keeps working for 7 days so builds you already shipped keep working; **Stop it now** ends it early. A secret key (`hinto_sk_…`, from Settings > API keys) is for servers and coding agents only, and Hinto refuses it from a website or an app. **Pause Signal** stops customer requests immediately.

When your backend signs the token, it derives `sub` from its authenticated session. A client-supplied customer ID must never decide token identity. Tokens use HS256, the active signing key ID (`HINTO_SIGNAL_KID`) in `kid`, the Signal app ID (`HINTO_SIGNAL_APP_ID`) in `aud`, and `iat`/`exp` with lifetime at most 12 hours. Return the JWT with `Cache-Control: no-store`, keep it in memory, and mint a new token after sign-in or account switch. Sign-out clears the runtime before the next account paints.

The token can also carry optional `email`, `name`, and `company` string claims. Your backend reads them from the same server session or user record as `sub`, never from the request. Hinto trusts them for two things only. It matches the signed `email` to an existing customer in the same organization, so the ticket arrives with that customer as the requester. Otherwise it fills the claims into the ticket's **Keep** form for an operator to confirm. Hinto never creates a customer from claims on its own. It ignores a blank or non-string claim, and an `email` that is not shaped like an email address.

## Sign-in provider tokens

An organization can name the sign-in provider its apps already use (Supabase, Firebase, Clerk, Auth0, or another OpenID provider), so an app without a backend passes that provider's token instead of one your backend signs. An organization admin names it, by approving a pairing that carries it, with the MCP, or in Settings > Hinto Signal. A Signal app trusts one provider. A request to trust a different one is refused with `identity_provider_conflict` until an admin changes it in Settings, and **Remove** stops Hinto accepting the provider's tokens at once.

Hinto checks every provider token:

* **Asymmetric signatures only.** The token is signed with RS256, RS384, RS512, PS256, ES256, ES384, or EdDSA. HS256 is reserved for tokens signed with your Signal signing secret, so a provider token is never checked against that secret, and an HS256 token never reaches the provider check.
* **Issuer and audience pinned.** `iss` must equal the issuer derived from what the admin entered, and `aud` must contain the provider's audience: `authenticated` for Supabase, the project ID for Firebase, and the entered audience for Auth0 and other OpenID providers. Clerk session tokens carry no audience, so Hinto checks only their issuer. Another OpenID provider must have an audience, because one issuer can sign tokens for many apps.
* **Keys fetched over public HTTPS.** Hinto reads the provider's public keys (JWKS) from the provider's own HTTPS address, never a private or local network address, with no redirects, a timeout, and a size limit. For another OpenID provider it reads `<issuer>/.well-known/openid-configuration` once, when the provider is saved, and refuses a document that names a different issuer. Keys are cached for about 10 minutes. A token signed with a key the cache does not hold refetches the keys at most once a minute, which is how a provider's key rotation is picked up.
* **Times and subject.** The token needs `sub`, `iat`, and `exp`, may live at most 12 hours, and is checked with 60 seconds of clock tolerance. `sub` is the customer's identity, and the SDK refuses a token whose `sub` is not the `subject` the app passed.
* **Verified email only.** Hinto takes `email` only when the token carries a top-level `email_verified: true` claim. It never reads verification from `user_metadata`, because Supabase lets the signed-in user write that object, so a Supabase token gives no email. The name comes from `name`, `user_metadata.full_name`, or `user_metadata.name`. No company is taken from a provider token. These claims are used the same way as claims your backend signs: to match an existing customer or fill the **Keep** form, never to create a customer on their own.

Anyone who can sign in to your app with that provider can open a support conversation as themselves. That is the same reach your backend's token endpoint gives a signed-in user. If the provider allows anonymous sign-in, such as Supabase anonymous users, those users count as signed in too.

## Exact origins and sessions

List each website's complete scheme, host, and port. A coding agent's pairing adds the origins it sends; without an agent, an admin chooses **Add website** in Settings > Hinto Signal. Wildcards, paths, credentials, and mixed-case origins are rejected. The list holds up to 10 websites. One list gates both support requests and session capture from a browser. A new website can take up to one minute to pass the session capture cache. The customer ID in the token must match the capture `external_id` identity for session attachment.

A conversation belongs to the authenticated subject and organization. Hinto returns customer messages and successfully delivered human replies in its customer transcript. Internal notes, pending or failed replies, and legacy widget records do not appear there. A claimed historical widget delivery is cancelled without a network send. If your product records sensitive fields, configure capture privacy controls before initializing the SDK; see [privacy controls](/privacy).

## Browser and server boundaries

The root browser SDK and IIFE contain capture only. Import the headless runtime from `@gethinto/browser-sdk/conversation` and styled React components from `@gethinto/native-support-react`. CSS is compiled and has no runtime injection. Server-side rendering may import the component package, but the runtime must be created only in a browser. Content Security Policy must permit your API and your token endpoint, or your sign-in provider when it supplies the token. The release has no public token mint endpoint; the lab's synthetic login runs only on loopback and is not production authentication.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.