Skip to content

Conversation

@nicknisi
Copy link
Member

@nicknisi nicknisi commented Dec 3, 2025

Summary

This PR upgrades @workos/authkit-session to 0.3.0 and fixes critical session persistence issues.

Problem: Can't Use TanStack's Built-in setResponseHeaders

TanStack Start provides setResponseHeaders() for setting cookies from server functions. However, importing it breaks builds:

"Readable" is not exported by "__vite-browser-external"

This happens because TanStack's barrel exports pull in node:stream code that Vite can't handle. This is a known issue (TanStack/router#4022).

Impact: When refreshSession() or switchToOrganization() is called, the session cookie can't be persisted. Users switch orgs successfully, but on page refresh they revert to their previous org.

Solution: Context-Based Session Persistence

Instead of importing from @tanstack/react-start/server, we use middleware context to defer cookie persistence:

1. Middleware creates context with `__setPendingHeader` setter
2. Server function refreshes session → gets encryptedSession
3. Server function stores pending header via context setter
4. Middleware reads pending headers after args.next() completes
5. Middleware applies cookies to the response

This follows the standard middleware pattern used in Express/Koa/etc.

Additional Fixes

Changes

  • storage.ts - No TanStack server imports; uses context for headers
  • middleware.ts - Passes header setter through context, applies pending headers to response
  • auth-helpers.ts - Returns session data for middleware to persist
  • context.ts - Try-catch for graceful context access
  • server-functions.ts / actions.ts - Use context-based persistence

Related

@nicknisi nicknisi changed the title Upgrade authkit-session to 0.2.0 with session refresh support Fix client bundling and upgrade authkit-session to 0.2.0 Dec 3, 2025
@nicknisi nicknisi marked this pull request as ready for review December 3, 2025 17:06
@greptile-apps
Copy link

greptile-apps bot commented Dec 3, 2025

Greptile Overview

Greptile Summary

This PR upgrades @workos/authkit-session from 0.1.2 to 0.2.0 and fixes a critical client bundling issue (#18) where server-only dependencies (@workos-inc/node, pluralize) were leaking into client bundles, breaking Convex integration and Safari browser support.

  • Dynamic import pattern: Introduced authkit-loader.ts as a centralized orchestrator using await import() instead of static imports, with lazy-loaded cached instances
  • Session refresh propagation: Middleware now properly handles { auth, refreshedSessionData } from withAuth() and propagates Set-Cookie headers to the browser when sessions are refreshed
  • Shared auth helpers: Extracted common auth logic into auth-helpers.ts including getRawAuthFromContext(), refreshSession(), and decodeState()
  • Improved error handling: Added isAuthConfigured() checks and try-catch blocks in server actions for graceful degradation
  • Tests updated: All test mocks refactored to use the new async getAuthkit() pattern instead of static imports

Confidence Score: 5/5

  • This PR is safe to merge - it's a well-structured refactoring that fixes a critical bundling issue with proper test coverage.
  • The changes are architecturally sound, following established patterns for dynamic imports in SSR frameworks. The PR properly addresses the root cause of issue @workos-inc/node is being loaded in browser causing "pluralize module not found" error with Convex integration #18 by introducing lazy-loaded server dependencies. Tests have been updated to match the new patterns, and the code maintains backward compatibility for existing users.
  • No files require special attention - all changes are well-tested and follow consistent patterns.

Important Files Changed

File Analysis

Filename Score Overview
src/server/authkit-loader.ts 5/5 New centralized orchestrator for dynamic imports of server-only dependencies, using lazy loading with caching to prevent client bundling issues.
src/server/auth-helpers.ts 5/5 New shared auth utilities including getRawAuthFromContext, refreshSession, and decodeState - extracts common auth logic from multiple files.
src/server/actions.ts 5/5 Refactored to use new auth-helpers module, added isAuthConfigured() checks and try-catch blocks for graceful error handling.
src/server/middleware.ts 5/5 Updated to handle { auth, refreshedSessionData } return from withAuth() and propagate Set-Cookie headers when sessions are refreshed.
src/server/server-functions.ts 5/5 Refactored to use auth-helpers and dynamic authkit loading. signOut now uses authkit.signOut() instead of manually constructing cookies.
src/server/server.ts 5/5 Callback handler refactored to use auth-helpers. Header extraction simplified to check both response headers and direct headers object.
package.json 5/5 Upgraded @workos/authkit-session from ~0.1.2 to 0.2.0 and updated dev dependencies.

Sequence Diagram

sequenceDiagram
    participant Client as Client Bundle
    participant ServerFn as Server Function
    participant AuthHelpers as auth-helpers.ts
    participant Loader as authkit-loader.ts
    participant AuthKit as @workos/authkit-session

    Note over Client,AuthKit: Before (Static Import - Caused Bundling Issue)
    Client->>ServerFn: Import
    ServerFn->>AuthKit: Static import (bundled into client!)
    AuthKit--xClient: @workos-inc/node leaked to client

    Note over Client,AuthKit: After (Dynamic Import Pattern)
    Client->>ServerFn: Import (safe - no static server deps)
    ServerFn->>AuthHelpers: Call getRawAuthFromContext()
    AuthHelpers->>Loader: await getAuthkit()
    Loader->>AuthKit: await import('@workos/authkit-session')
    AuthKit-->>Loader: AuthService instance (cached)
    Loader-->>AuthHelpers: Return cached instance
    AuthHelpers-->>ServerFn: Return auth result
    ServerFn-->>Client: Response (server deps never bundled)
Loading

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

18 files reviewed, no comments

Edit Code Review Agent Settings | Greptile

@nicknisi nicknisi changed the title Fix client bundling and upgrade authkit-session to 0.2.0 Fix client bundling and upgrade authkit-session to 0.3.0 Dec 8, 2025
@briggsrrr
Copy link

🙏

- Create src/server/context.ts with AuthKitServerContext interface
- Add getAuthKitContext() and getAuthKitContextOrNull() helpers
- Remove `as any` casts from production code
- Rename _setPendingHeader to __setPendingHeader (deeper internal signal)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

@workos-inc/node is being loaded in browser causing "pluralize module not found" error with Convex integration

4 participants