---
changelog:
  category: Release
  version: 2.4.1
date: '2026-09-18T14:29:16Z'
seo:
  description: >-
    Argon2id password hashing — argon2id-wasm (Rust → WASM), ~10x faster in the
    Convex isolate. New hashes in standard PHC format…
title: convex-auth v2.4.1
type: changelog
---
## Highlights

- **Argon2id password hashing** — `argon2id-wasm` (Rust → WASM), ~10x faster in the Convex isolate. New hashes in standard PHC format (`$argon2id$v=19$m=19456,t=2,p=1$`); legacy packed, Better Auth scrypt, and PBKDF2 hashes still verify — no migration needed.
- **Passkeys, web + React Native/Expo** — registration, sign-in, revocation, and rename, bound to the caller's identity. Conditional-UI autofill on web; `react-native-passkeys`-backed ceremonies on iOS/Android verified by the same server actions. Validated end-to-end on both platforms.
- **Session hardening** — every session-validating path now rejects revoked sessions; session lists never expose raw tokens (`isCurrent` computed server-side, `revokeSession` takes `sessionId` with an ownership check); 2FA pending challenges are opaque hashed tokens, not JWTs.
- **Passkey revocation cascade** — sessions and refresh tokens minted by a passkey record `credentialId`; revoking the passkey (or detecting a cloned authenticator via signature-counter regression) revokes them all, across arbitrarily large histories including pre-`credentialId` legacy rows.
- **Admin dashboard** — impersonation with audited sessions, user search + detail panel, organization member/role management, audit-log filters.
- **Query exhaustion fixes** — all revocation and code-consume paths paginate to exhaustion; sessions, refresh tokens, and live codes beyond the first index page can no longer survive revocation.

## What's Changed

### Password hashing

- Switch password hashing to `argon2id-wasm`; WASM init failures now surface as errors instead of reading as "wrong password".

### Passkeys

- Passkey management (register, list, revoke, rename) bound to `ctx.auth.getUserIdentity()`.
- Non-increasing signature counter revokes the passkey and writes a `passkey_counter_regression` audit event (cloned-authenticator detection).
- `renamePasskey` mutation via `auth.renamePasskey`, `usePasskeys().rename`, `onRename` prop on `PasskeyManager`.
- `passkey.maxPasskeysPerUser` config (default 10), re-checked at verification time.
- `passkey.origin` accepts `string | string[]`; `attestationType`, `userVerification`, `residentKey`, `authenticatorAttachment` configurable.
- `usePasskeys({ autofill: true })` enables WebAuthn conditional-UI sign-in.
- Challenges record `rpID`, accepted origins, effective identifier, and UV policy at generation; verification uses stored values.
- Relaxed-UV passkey sign-in on a 2FA account returns `twoFactorRedirect`; the pending challenge carries `credentialId` so the minted session stays revocable with the passkey. Both `usePasskeys` hooks store the challenge token so `ConvexVerifyTwoFactorForm` completes the flow.
- Passkey revocation paginates all lookups to exhaustion, attributes legacy sessions via stored-JWT `identityId`, and consumes in-flight pending challenges.
- `usePasskeys` fetches ceremony options at invocation time, not mount — no stale challenges.
- Audit events: `passkey_registered`, `passkey_authenticated`, `passkey_renamed`, `passkey_revoked`.
- **React Native / Expo:** `usePasskeys` under `@vortex-api/convex-auth/react-native/passkeys` (optional `react-native-passkeys` peer). Configure `passkey.origin` per platform including `android:apk-key-hash:<hash>`.

### Sessions & 2FA

- `listSessions` no longer returns `token`; items carry server-computed `isCurrent`.
- `revokeSession` takes `{ sessionId }` with caller-ownership verification.
- `ConvexSessionList` drops `currentSessionToken` (web + React Native). **Migration:** `revokeSession({ token })` → `revokeSession({ sessionId })`; remove the `currentSessionToken` prop.
- `revokedAt` enforced on session resolution, token-verify action, bearer `/convex/token` and `/session`, MCP OAuth authorize, OAuth account linking, and `verifySession` (no more arbitrary-active-session fallback).
- Session-family revocation, `revokeSessionsForUser`, refresh-token revocation, password-reset revoke, and verification-code consume/revoke paths all paginate to exhaustion.
- `authAccounts` gains `by_user_provider_issuer`; `organization_members` gains `by_user_status`.

### Admin

- Safe impersonation: short-lived audited sessions, `IMPERSONATION_SESSION_DURATION_MS` config, banner + stop in the React example.
- `createUser`, `setRole`, `setUserPassword`, `listUsers` with search/filter/sort/pagination.
- `listAdminAudits` filters (`action`, `targetType`, `targetId`, `adminId`, `from`, `to`); `auditsFilters` dashboard controls.
- Member list/search/pagination, `updateMemberRole`, `removeMember` dashboard wiring.
- User search + detail side panel via `usersSearch`, `onViewUser`, `selectedUser`.

### React Native demo

- Single `react-native` version across the workspace; Metro native extensions; Expo SDK 57 alignment; Uniwind theme init + `accent-color` patch; session JWT no longer rendered in the header.

**Full Changelog**: https://github.com/VortexNYC/convex-auth/compare/v2.3.0...v2.4.1
