Resolving Multi-Instance ESHOPMAN Admin SSO Failures: A Cache Module Deep Dive

For ESHOPMAN developers managing scalable e-commerce platforms, ensuring robust and secure administrative access across multiple instances is crucial. A recent community discussion highlighted a specific challenge with ESHOPMAN Admin Google Single Sign-On (SSO) when migrating cache modules, leading to intermittent login failures in multi-instance deployments.

The Multi-Instance SSO Dilemma: Cache Module Migration

When ESHOPMAN Admin API instances are deployed behind load balancers, a common architecture for high availability, a dependency mismatch emerged during the transition from the deprecated Modules.CACHE to the newer Modules.CACHING module. The symptom: ESHOPMAN Admin Google SSO would fail intermittently, often every other attempt, resulting in a redirect loop and an error message like:

[AdminOAuth] Google callback failed: No state provided, or session expired
302 /admin-oauth/google/relay?state=591071ef... -> /app/login?error=oauth_failed

The Technical Deep Dive: Dependency Mismatch and Silent Failure

The root cause lies in how ESHOPMAN's authentication module handles OAuth state. This state, essential for security during the SSO redirect flow, is managed via a container dependency. The auth module's constructor explicitly looks for a dependency named cache:

// Simplified ESHOPMAN auth module snippet
constructor({ ..., cache }) { this.cache_ = cache }

setState: async (key, value, ttlSeconds) => {
  if (!this.cache_) { throw new EshopmanError(..., "Cache module dependency is required when using OAuth providers that require state") }
  this.cache_.set(key, value, ttlSeconds ?? 1200)
},
getState: async (key) => {
  const value = await this.cache_.get(key)
  if (value !== null && value !== undefined) { await this.cache_.invalidate(key) }
  return value
},

Crucially, Modules.CACHE registers under the cache key, while the modern Modules.CACHING registers under caching. Consequently, the authentication module, expecting cache, doesn't utilize Modules.CACHING.

The Multi-Instance Pitfall: In-Memory Fallback

If Modules.CACHE is omitted, ESHOPMAN silently defaults to an in-memory cache for the cache dependency. While this works for single-instance deployments, it catastrophically fails in a multi-instance setup. An OAuth state written to Instance A's memory will be unavailable if the callback is routed to Instance B by a load balancer, leading to the "No state provided" error. This silent downgrade makes diagnosis difficult, presenting as intermittent failures rather than a clear bug.

The Workaround: Ensuring Shared State

To mitigate this until ESHOPMAN's authentication module is updated, the recommended workaround is to explicitly declare and configure both Modules.CACHE and Modules.CACHING. It's vital that Modules.CACHE is configured to use a shared, persistent cache like Redis, ensuring OAuth state is accessible across all instances. Your package.json dependencies for caching might include:

{
  "dependencies": {
    "@eshopman/caching": "2.19.0",
    "@eshopman/caching-redis": "2.19.0",
    "@eshopman/cache-redis": "2.19.0" // This resolves Modules.CACHE to Redis
  }
}

Ensure your ESHOPMAN configuration explicitly resolves Modules.CACHE to your shared Redis instance.

Best Practices for ESHOPMAN Deployments

This scenario highlights key considerations for ESHOPMAN developers:

  • Always use a shared, persistent cache (e.g., Redis) for multi-instance ESHOPMAN deployments, especially for authentication and other stateful operations.
  • Be mindful of module dependency keys during upgrades and migrations.
  • Engage with the ESHOPMAN community for insights on module updates and best practices for HubSpot-integrated storefronts.

By implementing this workaround, ESHOPMAN users can maintain secure and reliable Admin SSO across their scalable, multi-instance environments, ensuring smooth storefront management within HubSpot.

Start with the tools

Explore migration tools

See options, compare methods, and pick the path that fits your store.

Explore migration tools