loginos

How do I make Supabase auth work across multiple domains?

loginos teamUpdated 6 min read

Short answer

You can’t share one Supabase session between different domains, because supabase-js keeps it in each site’s own local storage or cookies. Give every domain its own session instead, from a sign-in they all trust: an OpenID Connect provider that remembers the person, added to Supabase Auth as a custom provider. With loginos in front, the second domain signs in without a form.

You run several sites on one Supabase project, like app.example.com, example.net and a shop on its own domain. Someone signs in on the first site and is a stranger on the second. No Supabase setting changes that, because each site keeps its own session. What you can share is the sign-in: one place that remembers the person and hands every domain a session of its own.

Why doesn’t a Supabase login on one domain carry over to another?

A Supabase session is a short-lived access token, which is a JWT, plus a refresh token. Your app stores both. In the browser, supabase-js saves the session to local storage. With @supabase/ssr, it lives in cookies named sb-<project_ref>-auth-token by default.

Both stores belong to a single site. Local storage is per origin, and a browser sends a cookie only to the domain that set it. So example.net starts without a session, and signing in there creates a second, separate one.

Subdomains are the exception. @supabase/ssr accepts cookie options, so you can scope the session cookie to example.com and share it with app.example.com and shop.example.com. Separate domains, like example.com and example.net, never share cookies, as explained in sharing cookies between domains.

What do the Site URL and redirect URLs control?

Two settings in Supabase Auth’s URL configuration decide where Supabase may send people back. Neither one shares a session.

  • The Site URL is the default redirect when your code passes no redirectTo. Email confirmations and password resets depend on it.
  • The Redirect URLs are an allow list. Every redirectTo that your domains use must match an entry.

The allow list accepts wildcards. * matches any run of characters except the separators . and /, ** matches any run of characters, and ? matches one character that isn’t a separator. So https://*.example.com/** allows app.example.com and shop.example.com, but not a.b.example.com, because * stops at a dot. Supabase suggests wildcards for local development and preview URLs, and exact URLs in production. The redirect URL docs list the full syntax.

Adding all your domains to the list lets each one finish its own sign-in. It doesn’t make a session from one domain valid on another.

What are your options?

A central login domain that hands over tokens

One site, say login.example.com, signs people in, then redirects to example.net with the access and refresh tokens in the URL. example.net passes them to supabase.auth.setSession(). It works, with sharp edges:

  • Tokens in URLs leak. They end up in browser history, server logs and analytics. Supabase refresh tokens don’t expire, and each works once, so a leaked one is good until someone uses it.
  • Two domains fight over one session. When the second domain refreshes with a token the first one already used, outside a 10-second window, Supabase treats it as reuse, ends the whole session and revokes its refresh tokens. Both domains are signed out.
  • Every target needs a check. Unless the login site redirects only to domains on your own list, it hands tokens to any site that asks.

The safe version gives each domain a one-time code that its server exchanges for a session of its own. That is what an identity provider does, and the next two options use one. Single sign-on across domains explains the pattern.

Make your Supabase project the identity provider

Supabase Auth can act as an OAuth 2.1 and OpenID Connect provider. The feature is in beta and available on all plans. Your main site hosts the consent screen, at the Site URL plus an authorization path you choose, and your other domains sign in through it as OAuth clients. Their redirect URIs must match exactly: this feature doesn’t accept wildcards.

Put an external identity provider in front

Supabase documents two ways to use another provider:

  • As a sign-in provider. Supabase Auth sends people to the provider and then issues its own session on each domain. Since April 2026 this also works with custom providers: any provider that follows OAuth 2.0 or OpenID Connect, used through signInWithOAuth({ provider: "custom:…" }). Row Level Security keeps working with auth.uid().
  • As third-party auth. Supabase accepts the provider’s own JWTs. The guides cover Clerk, Firebase Auth, Auth0, AWS Cognito and WorkOS. The tokens must be signed with an asymmetric key, carry a kid header and include a role: "authenticated" claim, or Postgres runs the query as anon.

Either way, the provider keeps a session on its own domain. When your second domain sends someone there, a provider that remembers them sends them straight back, so they never see a second form.

How loginos does it

loginos is a hosted OpenID Connect provider for products that run on many domains. With Supabase, the honest split is identity through loginos and data in Supabase. You can connect them in two ways.

loginos as a custom provider in Supabase Auth

This keeps Supabase sessions and Row Level Security as they are.

  1. Supabase shows the callback URL to register with a provider, usually https://<project-ref>.supabase.co/auth/v1/callback. In the developer console, create a platform with that host as its domain, and set the callback path to /auth/v1/callback. loginos only redirects to https://<one of your domains><callback path>.
  2. Add loginos to Supabase as an OpenID Connect provider, with the app key as client ID and the app secret as client secret. The dashboard has New Provider with Auto-discovery (OIDC), or you can run this once on your server:
Run once on your server
import { createClient } from "@supabase/supabase-js"

const supabase = createClient(process.env.SUPABASE_URL!, process.env.SUPABASE_SECRET_KEY!)

await supabase.auth.admin.customProviders.createProvider({
  provider_type: "oidc",
  identifier: "custom:loginos",
  name: "loginos",
  issuer: "https://loginos.io",
  client_id: process.env.LOGINOS_APP_KEY!,
  client_secret: process.env.LOGINOS_APP_SECRET!,
  scopes: ["openid", "profile"], // no email: loginos doesn't verify addresses yet
  email_optional: true,
})
  1. On each domain, call signInWithOAuth({ provider: "custom:loginos", options: { redirectTo } }), and exchange the code in your callback route as the Supabase guides show. Add each domain’s callback route to the Redirect URLs.

Leave the email scope out on purpose. Supabase Auth requires verified email addresses from OAuth providers, and it links identities that share an address. loginos doesn’t verify email addresses yet, so keep them out of Supabase.

On a second domain, Supabase sends the person to loginos, loginos recognizes them and sends them back, and Supabase creates that domain’s session. There is no form. Supabase issues its own JWT, so loginos roles and permissions aren’t in it. If you need them, read them on your server with the Management API.

loginos for sign-in, Supabase for data

You can also sign people in with loginos directly on every domain and keep your own session there, with the routes from the quickstart. Then you get loginos’s domain tools and roles in every token. Your server talks to Supabase with a secret key and scopes every query to the loginos sub itself.

Don’t plan on Supabase checking loginos tokens for Row Level Security. loginos isn’t among Supabase’s third-party auth providers, and its tokens carry no role claim. In this setup your server is the gate, and a Supabase secret key never goes to the browser.

Frequently asked questions

Can two domains share one Supabase session?

Not safely. Each domain stores its own copy, and a refresh token works once, so two domains that refresh the same session end up revoking it. Give each domain its own session, issued after one shared sign-in.

Do wildcards in the redirect URL list share sessions?

No. Wildcards only decide where Supabase may send people back after signing in. Every domain on the list still signs in on its own and keeps its own session.

Which Site URL should I set when I have several domains?

Your main domain. The Site URL is one default for redirects and email links. Put every other domain in the Redirect URLs, and pass redirectTo from each domain so people return where they started.

Can Supabase verify loginos tokens directly?

Not as Supabase documents it today. Its third-party auth guides cover Clerk, Firebase Auth, Auth0, AWS Cognito and WorkOS, and each expects a role claim that loginos tokens don’t carry. Add loginos to Supabase Auth as a custom provider instead, or check access on your server.

One account for every domain you run

loginos is an OpenID Connect provider with passkeys, a user pool shared by all of your domains, roles in every token, and account linking for the users you already have. Add your platform and its domains in a few minutes.

Keep reading

All answers