# How do I make Supabase auth work across multiple domains?

> 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](https://loginos.io/answers/share-cookies-between-domains.md).

## 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](https://supabase.com/docs/guides/auth/redirect-urls) 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](https://loginos.io/answers/single-sign-on-across-domains.md) 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](https://loginos.io/developer), 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:

```ts title="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,
})
```

3. 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](https://loginos.io/docs/api.md).

### 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](https://loginos.io/docs/quickstart.md). 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.

---

Updated 2026-10-14. Web page: https://loginos.io/answers/supabase-auth-multiple-domains
