Repository navigation
Design pillar: identity state machine (HMAC/JWT first-class, no session leaks) #4
Copy link
Copy link
Closed
Labels
competitor-analysisDerived from OSS competitor issue patternsDerived from OSS competitor issue patternsdesign-pillarCore design decisionsCore design decisionsidentityidentify / HMAC / JWT / sessionidentify / HMAC / JWT / session
Description
Identity is the second-most-reported failure class across competitors — stale users, HMAC rejections, session leaks across logins, custom attributes dropped silently.
Evidence
- `Add support for auth_tokens in boot and update methods devrnt/react-use-intercom#820` — "Add support for `auth_tokens` in boot/update" Add support for auth_tokens in boot and update methods devrnt/react-use-intercom#820
- `Support for intercom_user_jwt prop devrnt/react-use-intercom#813` — "Support for `intercom_user_jwt` prop" (workaround stuffs JWT into `customAttributes`) Support for intercom_user_jwt prop devrnt/react-use-intercom#813
- `User Hash Property / Formatting devrnt/react-use-intercom#668` — "User Hash Property / Formatting" User Hash Property / Formatting devrnt/react-use-intercom#668
- `user_id and company_id is being removed in user payload devrnt/react-use-intercom#805` — "user_id and company_id being removed in user payload" user_id and company_id is being removed in user payload devrnt/react-use-intercom#805
- `Running
boot(IntercomProps)results in unknown user devrnt/react-use-intercom#563` — "Running `boot(IntercomProps)` results in unknown user" Runningboot(IntercomProps)results in unknown user devrnt/react-use-intercom#563 - `Support for user_hash for Identify Verification nhagen/react-intercom#61` — "Support for `user_hash` for Identity Verification" Support for user_hash for Identify Verification nhagen/react-intercom#61
- `Session reset and tokenId set not consistent crisp-im/crisp-sdk-web#32` — "Session reset and tokenId set not consistent" Session reset and tokenId set not consistent crisp-im/crisp-sdk-web#32
- `Impossible de changer de tokenId sans recharger la page crisp-im/crisp-sdk-web#19` — "Impossible de changer de tokenId sans recharger la page" Impossible de changer de tokenId sans recharger la page crisp-im/crisp-sdk-web#19
- `Crisp Session Continuity not working crisp-im/crisp-sdk-web#49` — "Crisp Session Continuity not working" Crisp Session Continuity not working crisp-im/crisp-sdk-web#49
- `setCompany does not include geolocation in payload crisp-im/crisp-sdk-web#51` — "setCompany does not include geolocation in payload" setCompany does not include geolocation in payload crisp-im/crisp-sdk-web#51
- `Login Callback Not Exposed for Error Handling multivoltage/react-use-zendesk#89` — "Login Callback Not Exposed for Error Handling" (JWT refresh flow) Login Callback Not Exposed for Error Handling multivoltage/react-use-zendesk#89
- `[CW-1980] setUser not work anymore chatwoot/chatwoot#7065` — "setUser not work anymore" [CW-1980] setUser not work anymore chatwoot/chatwoot#7065
- `[SDK] setUser() does not update existing contact fields (phone_number, country_code, etc.) chatwoot/chatwoot#13448` — "setUser() does not update existing contact fields" [SDK] setUser() does not update existing contact fields (phone_number, country_code, etc.) chatwoot/chatwoot#13448
- `setCustomAttributes call fails due to HMAC failed error chatwoot/chatwoot#3458` — "setCustomAttributes fails due to HMAC failed error" setCustomAttributes call fails due to HMAC failed error chatwoot/chatwoot#3458
Unified identity model
```ts
identify({
id: string
email?: string
name?: string
phone?: string
// Typed verification — per-provider discriminated union
verification?:
| { kind: "hmac"; hash: string } // Intercom, Chatwoot, Beacon, Gist
| { kind: "jwt"; token: string } // Drift, Freshchat
| { kind: "callback"; getToken: () => Promise } // Zendesk Messenger
}): Promise
```
Rules
- State machine: `anonymous → identified(u1) → identified(u2) → anonymous`. Every transition (a) calls provider-specific reset (b) verifies window object cleared (c) emits `onIdentityChange`.
- `identify()` returns a `Promise` that resolves only when the next ping confirms the new identity.
- Provider config flag `enforceVerification: true` makes `verification` required at the type level. Missing ⇒ compile error.
- Never compute HMACs in the browser. Document that `hash` must come from your server.
- For callback-based flows (Zendesk), invoke `getToken` on 401 refresh.
- Expose `onIdentityChange((prev, next) => …)` so consumers can mirror into their analytics.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
competitor-analysisDerived from OSS competitor issue patternsDerived from OSS competitor issue patternsdesign-pillarCore design decisionsCore design decisionsidentityidentify / HMAC / JWT / sessionidentify / HMAC / JWT / session
Activity
feat(#1,#4): queue-before-load + identity state machine
productdevbook commentedon Apr 16, 2026
Implemented in c5db75a — identity state machine with typed Verification discriminated union and onIdentityChange listener. 39 tests green.