{organization_name} based Redirect URI with Apache

Hello all,

I’m currently in the process of creating a B2B SaaS application that requires each customer to have a separate tenant which is an entirely separate server.

I’m running an Apache server to host the front-end that passes API calls back to a Node backend.

My Apache mod_auth_openidc configuration is below

OIDCProviderMetadataURL https://[MY DOMAIN].us.auth0.com/.well-known/openid-configuration

OIDCClientID ${APACHE_OIDC_CLIENT_ID}

OIDCClientSecret ${APACHE_OIDC_CLIENT_SECRET}

OIDCScope “openid name email”

OIDCRedirectURI “https://[CLIENT].[PRODUCT NAME].com/redirect-uri”

OIDCCryptoPassphrase ${APACHE_OIDC_CRYPTO_PASSPHRASE}

I have “https://{organization_name}.[PRODUCT NAME].com/redirect-uri” specified as a valid callback in Auth0, yet when I try to login I get the following error

Callback URL mismatch.
The provided redirect_uri is not in the list of allowed callback URLs.
Please go to the Application Settings page and make sure you are sending a valid callback url from your application.

However, when I hardcode the subdomain for the client in as an allowed redirect uri: https://[CLIENT].[PRODUCT].com/redirect-uri, then it works- however it works for ALL users in my Auth0 domain, not just the ones that are part of the target organization.

Any help would be greatly appreciated, thank you!

Hi @BitshiftNate,

Welcome to the Auth0 Community!

The Auth0 Dashboard requires explicit, static URLs in the “Allowed Callback URLs” field. You can’t use a wildcard like https://{organization_name}.[PRODUCT NAME].com/redirect-uri or template variables that Auth0 would evaluate. When using an identity provider like Auth0, the redirect_uri sent in the initial request needs to match a value configured in the application settings exactly.

The solution to your architecture, where each customer has a distinct, server-side-hosted subdomain, is to route all tenants through a single, static Redirect URI and then handle the post-login routing on your side.

First, change your mod_auth_openidc configuration to use a universal, static subdomain that all tenants temporarily hit:

OIDCRedirectURI "https://sso.[PRODUCTNAME].com/redirect-uri"

In your Auth0 Dashboard, you would then configure only this one URL:

  • Allowed Callback URLs: https://sso.[PRODUCT NAME].com/redirect-uri

After that, you need to tell the user’s browser where to go next (back to their specific tenant subdomain). You can use a Post-Login Action to inject this routing information.

Use the user’s app_metadata or the context of the login to determine the correct tenant subdomain and then pass that information back to the app.

Here is an example of a Post-Login Action:

/**
 * Handler that will be executed after a successful login
 *
 * @param {Event} event - Details about the login context.
 * @param {PostLoginAPI} api - Interface for interacting with Auth0.
 */
exports.onExecutePostLogin = async (event, api) => {
  // 1. Determine the user's tenant/organization.
  //    This logic depends on where you store the tenant ID (e.g., user's app_metadata, a custom database lookup, or an organization ID if using the Organizations feature).

  const userTenant = event.user.app_metadata.tenant_subdomain; // Assuming you store it here

  if (userTenant) {
    // 2. Add the target tenant's subdomain to the ID Token/Access Token.
    //    We'll use a custom claim namespace to ensure it's not confused with standard claims.
    const namespace = "https://[PRODUCT NAME].com/claims";
    api.idToken.setCustomClaim(`${namespace}/tenant`, userTenant);
    api.accessToken.setCustomClaim(`${namespace}/tenant`, userTenant);
  }
};

After the user is redirected to https://sso.[PRODUCT NAME].com/redirect-uri, your Apache server’s mod_auth_openidc will receive the token.

  • Your server must then inspect the token to read the custom tenant claim you injected in the Action.
  • The server then performs an internal redirect (or a 302 redirect back to the client) to the correct, secured URL: https://[tenant].sso.[PRODUCT NAME].com/dashboard.

If you have any further questions, please don’t hesitate to reach out.

Have a good one,
Vlad

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.