This release adds 3 notable features for engineering teams evaluating rollout.
✓ No known CVEs patched in this version
Topics
+8 more
Affected surfaces
ReleasePort's take
Moderate signalReleasePort v0.8.9 introduces opt‑in identity verification using signed JWT tokens for `identify()` and `group()` SDK calls.
Why it matters: Enables token‑based impersonation prevention; operators must configure signing secrets in the new Identity Verification settings before enabling to secure traffic.
Summary
AI summaryIdentity verification adds signed JWT tokens to prevent impersonation via identify()/group() calls.
Changes in this release
| Type | Severity | Summary | CVE |
|---|---|---|---|
| Security | Critical |
Adds opt‑in identity verification using signed JWT tokens. Adds opt‑in identity verification using signed JWT tokens. Source: llm_adapter@2026-07-16 Confidence: high |
— |
| Feature | Medium |
Adds Identity Verification settings page for managing signing secrets and rotating them. Adds Identity Verification settings page for managing signing secrets and rotating them. Source: llm_adapter@2026-07-16 Confidence: high |
— |
| Feature | Medium |
Adds "Signed traffic" coverage card showing percentage of identify()/group() calls with valid tokens. Adds "Signed traffic" coverage card showing percentage of identify()/group() calls with valid tokens. Source: llm_adapter@2026-07-16 Confidence: high |
— |
| Feature | Medium |
Adds "Validate a token" tool in Identity Verification settings to debug token verification failures. Adds "Validate a token" tool in Identity Verification settings to debug token verification failures. Source: llm_adapter@2026-07-16 Confidence: high |
— |
| Refactor | Low |
Restricts identity verification to the v2 WebSocket surface; REST API and v1 socket remain unchanged. Restricts identity verification to the v2 WebSocket surface; REST API and v1 socket remain unchanged. Source: llm_adapter@2026-07-16 Confidence: high |
— |
Full changelog
This release lets you prove that identify() and group() calls really come from your app, so your public environment token stops being enough to impersonate your users. Your backend signs a short JSON Web Token for each logged-in user; Usertour verifies it before accepting the identity. Verification is opt-in per environment and rolls out safely — unsigned traffic keeps working while a coverage meter shows you when it's safe to switch enforcement on.
What's Changed
🔐 Prove user identities with a signed token
Your environment token ships in every visitor's page source — it has to, so the SDK can connect. That means the token alone can't prove who is calling: anyone who has viewed your page could call identify() with someone else's user ID and read or overwrite that user's data. Identity verification closes this. Your backend mints a JWT (HS256) signed with a per-environment signing secret only you hold, carrying the user's ID as the sub claim (and optionally the company as companyId). Pass it to the SDK — usertour.identify(userId, attrs, { token }) — and Usertour rejects any identity claim that isn't backed by a valid token. One token proves both the user and their company membership. See the Identity Verification guide for backend signing samples in Node, Python, Ruby, PHP and Go.
🎛️ A new Identity Verification settings page
Settings → Identity Verification manages the whole lifecycle: generate a signing secret, copy it into your backend, and rotate it with zero downtime — a new secret and the old one are both accepted until you revoke the old one, and a Last used timestamp tells you when it's safe to revoke. A built-in Validate a token tool takes a token you've generated and tells you exactly whether it verifies, and if not, why — expired, wrong signature, wrong algorithm, missing claim — so you debug the real problem instead of guessing.
📊 Coverage-first, opt-in enforcement
Turning on enforcement while some of your pages still send unsigned identities would lock those users out, so the release is built to prevent that. Even with enforcement off, Usertour verifies every identity claim and records the result. The Signed traffic card shows the share of identify() and group() calls over the last 7 days that carried a valid token; when it reads 100%, you flip Require identity verification on with confidence. Anonymous visitors (identifyAnonymous()) stay exempt — they involve no backend, so they can't be signed — and keep working with enforcement on.
🔑 What identity verification does and doesn't cover
With enforcement on, the environment token is no longer a write credential: nobody can impersonate your users, mass-create fake users, or attach users to companies they don't belong to. It deliberately doesn't try to hide published content (that's served to anonymous visitors by design) or stop a real signed-in user from editing their own attributes. Signing secrets are stored encrypted at rest and are only ever visible to workspace owners, alongside your API keys.
🛠️ Under the hood
Identity verification is a single verification path feeding an opt-in gate, designed across ADR 0008 (the verification model) and ADR 0009 (the JWT token format, which replaced an initial bare-HMAC design before release):
- One
checkTokenclassifier is the single source of truth for both the runtime handshake and the console validator, so they can never disagree. Claim comparison is string-coerced (numeric IDs),exp/nbfcarry a 30-second clock tolerance, tokens are length-bounded before any decode on the unauthenticated handshake path, and a handshake with a company claim verifies its token exactly once. - Signing secrets live in a dedicated
EnvironmentSigningSecrettable —utv_-prefixed, AES-256-GCM encrypted at rest (HMAC needs the original value, so hashing is impossible by construction), at most two active per environment for the rotation window, withlastUsedAtobservability. The lifecycle mutations run in serializable transactions that retry on serialization failure. - The SDK keeps a single identity token as the source of truth for reconnect credentials: a refreshed token revives a handshake that was rejected while a token was expiring, and a server-rejected
group()claim rolls back with concurrency-safe compare-and-restore so it can never poison a later reconnect. - Verification runs only on the v2 WebSocket surface; the REST API already authenticates with secret, server-side keys, and the v1 socket path is out of scope as it winds down.
Full Changelog: https://github.com/usertour/usertour/compare/v0.8.8...v0.8.9
Weekly OSS security release digest.
The CVE patches and breaking changes that affected production tools this week. One email, every Sunday.
No spam, unsubscribe anytime.
Share this release
About usertour
Usertour is an open-source user onboarding platform. It allows you to create in-app product tours, checklists, and surveys in minutes—effortlessly and with full control.The open-source alternative to Userflow and Appcues
Related context
Related tools
Beta — feedback welcome: [email protected]