Skip to content

Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

[Unreleased]

Added

  • JaduAuthProvider now injects a <link rel="preconnect" crossorigin="use-credentials"> for the apiUrl origin on mount, warming the DNS + TCP + TLS handshake that the mount-time GET /api/auth/sso/me probe would otherwise pay cold. The probe is usually the only request on the page pointed at the auth origin, so it is the only one exposed to handshake packet loss — a single dropped SYN there costs seconds of kernel retransmit backoff. For the hint to buy real lead time it should also go in the app's HTML <head>, where the browser can start the handshake during HTML parse instead of at React mount; see the README. use-credentials is required, since the probe sends credentials: "include" and a socket opened in another credentials mode is not reused for it.

Fixed

  • The mount-time GET /api/auth/sso/me probe now times out after 15s instead of 5s. On a lossy path a dropped TCP SYN (1-7s of kernel retransmit backoff) plus the CORS preflight round trip regularly pushed a healthy session past 5s, and the abort showed a signed-in user the "couldn't sign you in" screen.
  • Impersonation no longer ends on a page reload. It is carried by the access token, never the session token, so the mount-time GET /api/auth/sso/me probe authenticates the real session and answers as the real user — initializeAuth was adopting that response and overwriting the impersonated access token, spine token and cached user. It now keeps the impersonated set when a valid impersonation access token is stored, and restores originalUser so the banner survives too. Consumers that reload from onImpersonationStart (the documented way to refetch as the impersonated user) were losing impersonation every time.
  • An expired impersonation token now lapses back to the real user, clears the stored original, and fires onImpersonationEnd — restoring 1.5.x behaviour.
  • Redeeming a ?code (a brand-new session) drops any impersonation left over from the previous one instead of adopting it.

Removed

  • onSessionProbe provider prop and SessionProbeResult type, briefly published in 2.0.5. Probe telemetry will return as built-in SDK logging.

[2.0.0] - JaduSSO

BREAKING. The SDK is now JaduSSO-only. Tenants no longer own login UI; login lives on jadu-account, and the SDK handles the cookie-based session probe + impersonation + RBAC reads. Major version bump reflects the removed credential surface and the provider/option renames below.

Added

  • startJaduSSO(overrides?) on useJaduAuth() — arg-less SSO redirect that reads jaduSSOUrl + authAppId from the provider and defaults returnTo to the current URL, then sends the browser to jaduSSOUrl/login?appId=…&returnTo=…. Tenants render a "Login using JaduAccount" button that calls startJaduSSO().
  • jaduSSOUrl prop on JaduAuthProvider — the jadu-account login host used by startJaduSSO().
  • buildJaduSSOUrl(opts) (@scenarix/jadu-auth and @scenarix/jadu-auth/react) — lower-level URL builder for SSR, anchor hrefs, or tests where there's no hook context. Takes { jaduSSOUrl, appId, returnTo }.
  • JaduAuthProvider performs a cookie-only GET /api/auth/sso/me on mount with x-auth-app-id. The BE verifies cookie + RBAC for the app in a single trip and returns { user, accessToken, sessionToken, jaduSpineToken }. The SDK seeds local storage with the result so authenticatedAxios, canUserDo, scheduled refresh, and impersonation all work without further round trips.
  • autoSSORedirect prop on JaduAuthProvider (default false) — when enabled, the mount-time probe auto-redirects to JaduSSO login on a clean 401/403 instead of waiting for a button click. Requires jaduSSOUrl. A per-tab loop guard (sessionStorage) caps consecutive auto-redirects so a non-returning session cookie can't cause an infinite redirect loop; transient/network failures and explicit logout() never auto-redirect.
  • ssoRedirecting and ssoRedirectBlocked on the useJaduAuth() surface — drive a "Signing you in…" placeholder vs. the manual fallback button.

Removed

  • JaduAuthMode and the mode prop on JaduAuthProvider. v2 is the only flow.
  • All credential-owning methods on useJaduAuth(): loginWithEmailPassword, signupWithEmailPassword, forgotPasswordInit, forgotPasswordVerify, sendVerificationEmail, verifyEmail, signupInitWithEmailOtp, signupVerifyWithEmailOtp, loginInitWithEmailOtp, loginVerifyWithEmailOtp, loginInitWithSmsOtp, loginVerifyWithSmsOtp, refreshToken, simulateAccessTokenExpiry. Login is jadu-account's job.
  • Strategy blocks on AuthClient: emailPassword.*, emailOtp.*, smsOtp.*. Use jadu-account's BE directly if you need to drive credential flows server-side.
  • AuthErrorCode.NOT_SUPPORTED_IN_V2 (no longer reachable), AuthErrorCode.INVALID_CREDENTIALS, AuthErrorCode.USER_ALREADY_EXISTS. InvalidCredentialsError, UserAlreadyExistsError.
  • Type re-exports: AuthStrategies, LoginRequest, SignupRequest, VerifyEmailRequest, SendVerificationEmailRequest, SignupResponse, isSignupResponse, JaduAuthMode, SignupResult.

Changed

  • Renamed the jaduAuthUrl provider prop / JaduSSOOptions field → jaduSSOUrl (also buildJaduSSOUrl({ jaduSSOUrl, … })). Update call sites.
  • The provider's session probe moved from GET /api/auth/me to the new cookie-only GET /api/auth/sso/me.

Backend (additive — no removals)

  • New GET /api/auth/sso/me (cookie-only, behind authenticateSessionCookieOnly). Requires x-auth-app-id (rejected with 400 if missing) and returns { user, accessToken, jaduSpineToken, sessionToken }. Bearer-only requests are rejected at 401.
  • Legacy GET /api/auth/me is unchanged (still cookie-or-Bearer, returns { user }), so existing SDK versions keep working. v1 cleanup is deferred.
  • logout now clears the session cookie with the full cookie options (path + domain) so it actually clears in production.
  • New optional SESSION_COOKIE_DOMAIN env (e.g. .studiojadu.com in prod) for cross-subdomain SSO; unset in dev.

Fixed

  • be/src/index.ts: wait for async error logging to flush before exiting on uncaughtException.
  • useJaduAuth: preserve optimistic setUser(cachedUser) for non-impersonation session restores while still keeping impersonation-safe cleanup.
  • package/src/server/jaduAuth.ts: temporarily relax JWT authAppId enforcement (fall back to configured appId) to unblock production token validation.

[1.5.0]

Removed

  • AuthClient.getSessions() and GET /api/auth/sessions — not implemented on jadu-auth server
  • AuthClient.changePassword() and useJaduAuth().changePassword — POST /api/auth/change-password not implemented on jadu-auth server

[0.1.0] - 2025-02-09

Added

  • Initial release of @scenarix/jadu-auth
  • JaduAuthProvider and useJaduAuth React integration
  • AuthClient for low-level auth API calls
  • createAuthenticatedAxios with automatic token refresh
  • JaduAuth server SDK for JWT verification
  • Email verification, password reset, and forgot password flows

Fixed

  • getMe response shape: Backend returns { data: { user: User } }; SDK now correctly extracts user instead of treating entire data as User
  • Error mapping: When backend omits error.code, SDK now infers error type from HTTP status (400→VALIDATION_ERROR, 401→SESSION_EXPIRED, etc.)
  • EMAIL_NOT_VERIFIED: Added handling for backend errorCode: 'EMAIL_NOT_VERIFIED' in error responses

Changed

  • Replaced magic number 15 * 60 * 1000 with DEFAULT_ACCESS_TOKEN_TTL_MS constant
  • Unified debug log prefix to [JaduAuth] across authClient and authenticatedAxios
  • Made ApiErrorResponse.error optional to align with backend response shape
  • Added appId to provider init effect dependencies

Added (API)

  • changePassword(currentPassword, newPassword) on useJaduAuth for authenticated password changes
  • VERSION and SDK_NAME exports from main package
  • Security note in TokenStorage JSDoc regarding localStorage and XSS

Removed

  • getAuthClient and initAuthClient (unused singletons; use new AuthClient(config) instead)