Multi-tenant (white-label app) design with subdomains
Hi, my nextjs app allows users to create their own apps to service their users, accessed by a subdomain (aka white labelling). I’m developing on localhost and getting state errors in the auth routing.
ITEM 1: Main app is working fine using a custom login page with http://localhost:3000 but I get state error (different id) with “app” subdomain:- HOME and LOGOUT URIs: http://localhost:3000 (can use http://app.localhost:3000 if fix requires it) LOGIN URI: http://app.localhost:3000/login REDIRECTS: http://app.localhost:3000/api/auth/kinde_callback , http://app.localhost:3000/api/auth/login-callback KINDE_COOKIE_DOMAIN= “.localhost” I’m testing with Google auth. They don’t allow localhost redirects in allowed callbacks on their site and I wonder if redirecting back to “app.localhost” is a problem???
ITEM 2: Client apps essentially have the same URL pattern as above except for using their subdomain vs. “app” subdomain. I programmatically create a new application in Kinde when a user deploys their app. Callbacks as follows: - HOME and LOGOUT URIs: http://someapp.localhost:3000 LOGIN URI: http://someapp.localhost:3000/login REDIRECTS: http://someapp.localhost:3001/api/auth/kinde_callback , http://someapp.localhost:3001/api/auth/login-callback NB: I’m using org_codes to represent organizations of users. One user database across all apps and app access granted to organization by subscription (using features). 1) Do I need a Kinde application for each “app”, or can I leverage subdomain wildcards and KINDE_COOKIE_DOMAIN? All subdomain apps will use the same authentication methods (Google, email etc) but each app will have its own custom login pages for uniqueness and white labelling. 2) Why am I getting state errors for app.localhost? Do I need to use a domain like "localtest.me" or explicitly add entries in hosts file for local development? 3) Am I using Kinde the best way for my app? Is there a better alternative design?
ITEM 1: Main app is working fine using a custom login page with http://localhost:3000 but I get state error (different id) with “app” subdomain:- HOME and LOGOUT URIs: http://localhost:3000 (can use http://app.localhost:3000 if fix requires it) LOGIN URI: http://app.localhost:3000/login REDIRECTS: http://app.localhost:3000/api/auth/kinde_callback , http://app.localhost:3000/api/auth/login-callback KINDE_COOKIE_DOMAIN= “.localhost” I’m testing with Google auth. They don’t allow localhost redirects in allowed callbacks on their site and I wonder if redirecting back to “app.localhost” is a problem???
ITEM 2: Client apps essentially have the same URL pattern as above except for using their subdomain vs. “app” subdomain. I programmatically create a new application in Kinde when a user deploys their app. Callbacks as follows: - HOME and LOGOUT URIs: http://someapp.localhost:3000 LOGIN URI: http://someapp.localhost:3000/login REDIRECTS: http://someapp.localhost:3001/api/auth/kinde_callback , http://someapp.localhost:3001/api/auth/login-callback NB: I’m using org_codes to represent organizations of users. One user database across all apps and app access granted to organization by subscription (using features). 1) Do I need a Kinde application for each “app”, or can I leverage subdomain wildcards and KINDE_COOKIE_DOMAIN? All subdomain apps will use the same authentication methods (Google, email etc) but each app will have its own custom login pages for uniqueness and white labelling. 2) Why am I getting state errors for app.localhost? Do I need to use a domain like "localtest.me" or explicitly add entries in hosts file for local development? 3) Am I using Kinde the best way for my app? Is there a better alternative design?
3 Replies
I just discovered Google auth doesn't allow subdomains of localhost. That answers that question. But I'd appreciate feedback on whether wildcards can be used or I need a separate application for each "app" attached to a subdomain. Thx.
Hi Dave, thanks for the detailed explanation.
Here’s a concise breakdown to help address your questions around multi-tenant subdomain support and Kinde configuration:
1. Google OAuth does not allow redirect URIs using
For example:
2. Kinde supports wildcards in callback URLs:
Docs:
https://docs.kinde.com/get-started/connect/callback-urls
https://docs.kinde.com/build/domains/subdomains-for-callbacks
3. You do not need to create a separate Kinde Application for each subdomain/tenant. Instead, use Kinde Organizations to represent each tenant. Each organization has a unique handle (e.g.,
Docs: https://docs.kinde.com/build/organizations/multi-tenancy-using-organizations
4. To enable shared authentication state across subdomains, set the
Docs: https://docs.kinde.com/developer-tools/sdks/backend/nextjs-sdk
5. If your architecture evolves to include multiple Kinde applications, Kinde also supports shared sessions to allow seamless navigation without repeated login prompts.
Docs: https://docs.kinde.com/authenticate/manage-authentication/user-auth-applications Please let us know if you need further help with any part of the setup—we’d be happy to assist
1. Google OAuth does not allow redirect URIs using
*.localhost
domains, which is likely the cause of the state mismatch error you're encountering. A common workaround is to use a domain like localtest.me
, which resolves to 127.0.0.1
and is accepted by Google.For example:
http://app.localtest.me:3000
can be safely registered in your Google OAuth Console.2. Kinde supports wildcards in callback URLs:
https://*.yourdomain.com/api/auth/kinde_callback
For production, you can also use dynamic callbacks with organization handles:https://{organization.handle}.yourdomain.com/api/auth/kinde_callback
Docs:
https://docs.kinde.com/get-started/connect/callback-urls
https://docs.kinde.com/build/domains/subdomains-for-callbacks
3. You do not need to create a separate Kinde Application for each subdomain/tenant. Instead, use Kinde Organizations to represent each tenant. Each organization has a unique handle (e.g.,
org_ABC123
), and users are scoped appropriately within a single application.Docs: https://docs.kinde.com/build/organizations/multi-tenancy-using-organizations
4. To enable shared authentication state across subdomains, set the
KINDE_COOKIE_DOMAIN
in your environment variables to .yourdomain.com
. This allows all subdomains (e.g., app.yourdomain.com
, client.yourdomain.com
) to access the same session cookie.Docs: https://docs.kinde.com/developer-tools/sdks/backend/nextjs-sdk
5. If your architecture evolves to include multiple Kinde applications, Kinde also supports shared sessions to allow seamless navigation without repeated login prompts.
Docs: https://docs.kinde.com/authenticate/manage-authentication/user-auth-applications Please let us know if you need further help with any part of the setup—we’d be happy to assist
I already do for users/organizations. But my application is also "multi-app", which is denoted by subdomains.