#Convex Auth Subdomains

14 messages · Page 1 of 1 (latest)

coarse quarry
#

How can I use convex auth on subdomains? I need users to be able to sign in on domain.com and slug.domain.com. I have a multi-tenant application where subdomains are dynamic.

grave summitBOT
#

Hi @coarse quarry. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:

#

There are two related pieces here:

  1. Sharing Convex Auth sessions across subdomains
  2. Handling redirects / callback URLs for multiple domains

1. Sharing Convex Auth sessions across subdomains

By default, Convex Auth stores tokens in localStorage, which is not shared across subdomains. To make a single Convex Auth session work on domain.com and slug.domain.com, you can switch to a cookie-based TokenStorage and set the cookie domain to the “root” domain (e.g. .domain.com). This lets all subdomains see the same auth token.

From the Discord thread, the working pattern is:

// utils/getRootDomain.ts
function getRootDomain(): string {
  const hostname = window.location.hostname;
  const parts = hostname.split(".");
  if (parts.length >= 2) {
    return `.${parts.slice(-2).join(".")}`; // ".example.com"
  }
  return hostname;
}
// utils/cookieStorage.ts
import { TokenStorage } from "@convex-dev/auth/react";

export const cookieStorage: TokenStorage = {
  getItem: (key) => getCookie(key),
  setItem: (key, value) => setCookie(key, value, { domain: getRootDomain() }),
  removeItem: (key) => deleteCookie(key, { domain: getRootDomain() }),
};

Then pass this storage into your provider:

import { ConvexAuthProvider } from "@convex-dev/auth/react";
import { cookieStorage } from "@/utils/cookieStorage";

<ConvexAuthProvider client={convex} storage={cookieStorage}>
  {children}
</ConvexAuthProvider>

This setup was reported to keep users authenticated across all subdomains, including in production, as long as the cookie domain is the shared root (e.g. .example.com). [convex auth subdomains]

#

Because your subdomains are dynamic (slug.domain.com), this approach still works: getRootDomain() derives .domain.com at runtime from window.location.hostname, so any *.domain.com instance will share the same cookie.

2. Redirects / callback URLs for multiple domains

Convex Auth normally uses CONVEX_SITE_URL for sign‑in and callback URLs. For more complex setups (multiple apps / domains), you can:

  • Override the redirect behavior with the redirect callback in Convex Auth’s server config, so you can send users back to the specific subdomain they came from instead of always SITE_URL. [preview deployments & redirect]
  • Optionally set CUSTOM_AUTH_SITE_URL to a custom HTTP Actions domain if you’re using a Convex custom domain for auth flows. [custom auth site url; custom domains]

This lets you:

  1. Start auth from slug.domain.com
  2. Run the Convex Auth flow (possibly on a central auth domain / path)
  3. Redirect back to slug.domain.com using the redirect callback
  4. Rely on the shared cookie storage so the session is valid on both domain.com and slug.domain.com

What’s not first‑class yet

The docs and threads indicate:

  • Cross‑subdomain support is not yet a built‑in Convex Auth toggle; it’s achieved via the custom TokenStorage approach above. [convex auth subdomains]
  • There isn’t an official, fully documented “multi‑app / multi‑domain Convex Auth” guide; most patterns rely on customizing redirects and storage.
#

If you need more advanced enterprise auth or cross‑domain SSO beyond this, staff have suggested using providers like Clerk or WorkOS instead of Convex Auth. [is convex best choice]


Summary for your case

  • Use a cookie-based TokenStorage with domain: .your-root-domain.com so sessions are shared across domain.com and any slug.domain.com.
  • Use Convex Auth’s redirect callback (and possibly CUSTOM_AUTH_SITE_URL) to send users back to the correct subdomain after sign‑in.
  • This works with dynamic subdomains because the cookie domain is the shared root, not the specific slug.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:

#

@coarse quarry Kapa.ai is still learning and improving, please let me know how I did by reacting below.

coarse quarry
#

@grave summit How would I handle this in local development?

grave summitBOT
#

Let me check the knowledge base for you again. One moment! :books:

#

For local development you can use the same pattern, because the shared part of the hostname is still what matters.

From the Discord thread, the working approach is:

  1. Derive the “root” domain at runtime
function getRootDomain(): string {
  const hostname = window.location.hostname;
  const parts = hostname.split(".");
  if (parts.length >= 2) {
    return `.${parts.slice(-2).join(".")}`; // ".example.com"
  }
  return hostname;
}
  1. Use a cookie-based TokenStorage that sets the cookie on that root
import { TokenStorage } from "@convex-dev/auth/react";

export const cookieStorage: TokenStorage = {
  getItem: (key) => getCookie(key),
  setItem: (key, value) =>
    setCookie(key, value, { domain: getRootDomain() }),
  removeItem: (key) =>
    deleteCookie(key, { domain: getRootDomain() }),
};
  1. Pass it to ConvexAuthProvider in your app (including dev)
import { ConvexAuthProvider } from "@convex-dev/auth/react";
import { cookieStorage } from "@/utils/cookieStorage";

<ConvexAuthProvider client={convex} storage={cookieStorage}>
  {children}
</ConvexAuthProvider>

This was reported to work both in development and production, keeping users authenticated across all subdomains, as long as the cookie domain resolves to the shared root (e.g. .example.com). [convex auth subdomains]

#

For local dev you just need to ensure you’re actually using subdomains that share a root (e.g. app.localhost and tenant.localhost, or app.dev.example.test and tenant.dev.example.test); then getRootDomain() will compute the right cookie domain and the same code path works. The knowledge sources don’t go into more detail than this about localhost-specific quirks.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:

#

@coarse quarry Kapa.ai is still learning and improving, please let me know how I did by reacting below.

coarse quarry
#

@grave summit How would I implement the getCookie/setCookie/deleteCookie functions?

grave summitBOT
#

Let me check the knowledge base for you again. One moment! :books:

#

The knowledge sources don’t include concrete implementations of getCookie, setCookie, or deleteCookie; they only show how to use them inside a TokenStorage adapter. [convex auth subdomains]

So I can’t give you an “official” implementation, but I can outline the shape you need:

  • getCookie(name) → returns the cookie value (or undefined/null) as a string.
  • setCookie(name, value, options) → writes a cookie, including domain (for cross‑subdomain sharing), path, expires/maxAge, etc.
  • deleteCookie(name, options) → removes the cookie, usually by setting it with an expired date and same domain/path as when it was created.

You can implement these with any cookie library (e.g. js-cookie) or your own helpers, as long as:

Example wiring (pseudocode, not from docs):

export const cookieStorage: TokenStorage = {
  getItem: (key) => getCookie(key),
  setItem: (key, value) =>
    setCookie(key, value, { domain: getRootDomain(), path: "/" }),
  removeItem: (key) =>
    deleteCookie(key, { domain: getRootDomain(), path: "/" }),
};

Since the sources don’t specify a particular cookie library or exact implementation, you’re free to choose any standard cookie helper that matches this interface.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: