Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Configuring multiple auth0 applications at run time #600

Closed
jagathwee opened this issue Feb 22, 2022 · 16 comments
Closed

Configuring multiple auth0 applications at run time #600

jagathwee opened this issue Feb 22, 2022 · 16 comments
Labels
question Further information is requested

Comments

@jagathwee
Copy link

jagathwee commented Feb 22, 2022

Description

We configured two auth0 applications at runtime using manually created auth instances with InitAuth0(). Authentication fails with "invalid_grant (Invalid authorization code)." Please let me know: (1) whether this is supported, (2) if supported any hints on getting this to work. Thanks.

Reproduction

This is how we create the auth instance: For App1, we use the default parameters, whereas, for App2, we pass the config parameters.

import { initAuth0 } from '@auth0/nextjs-auth0';

export default (req?: { headers: { host: string } }) => {
  const isApp2 = req?.headers?.host.includes("App2 Domain");

if (isApp2) {
    return initAuth0({
      secret: process.env.AUTH0_SECRET_APP2,
      issuerBaseURL: process.env.AUTH0_ISSUER_BASE_URL_APP2,
      baseURL: process.env.AUTH0_BASE_URL_APP2,
      clientID: process.env.AUTH0_CLIENT_ID_APP2,
      clientSecret: process.env.AUTH0_CLIENT_SECRET_APP2,
      authorizationParams: {
        audience: process.env.AUTH0_AUDIENCE_APP2,
      },
    });
  }

  return initAuth0({});
}

With this setup, App1 works fine. The App2 authentication fails with the "invalid_grant (Invalid authorization code)" error.

Environment

AUTH0_SCOPE is the same for both apps.

@adamjmcgrath
Copy link
Contributor

Hi @jagathwee - this should work and I can't see anything wrong with the code you've shared in principle.

Invalid authorization code could mean that the redirect_uri you're using on callback is different from the one you were using on login. Are you doing anything custom at runtime to define a different redirect_uri at login? If so, you need to make sure it matches https://auth0.github.io/nextjs-auth0/interfaces/handlers_callback.callbackoptions.html#redirecturi in the callback

If it's not that, I'd need to see a running app that demonstrates the issue in order to debug it for you.

@adamjmcgrath adamjmcgrath added the question Further information is requested label Feb 24, 2022
@jagathwee
Copy link
Author

Hi @adamjmcgrath,

Thanks for the information. We did not explicitly configure CallbackOptions.redirectUri. Is this mandatory when we run multiple domains? From the following piece of documentation, it is not clear whether this is mandatory or not. Anyway, we will give it a try and let you know. Thanks.

--Doc--
This is useful to specify in addition to BaseConfig.baseURL when your app runs on multiple domains, it should match {@link LoginOptions.authorizationParams.redirect_uri}.
--End--

@adamjmcgrath
Copy link
Contributor

Thanks for the information. We did not explicitly configure CallbackOptions.redirectUri. Is this mandatory when we run multiple domains?

I'm not sure what you're doing exactly. But, what is mandatory is that you do the code exchange with the same redirect_uri that you logged in with (otherwise you get invalid_grant (Invalid authorization code))

@adamjmcgrath
Copy link
Contributor

Closing - feel free to ping me if you want to continue the conversation

@jagathwee
Copy link
Author

Hi @adamjmcgrath,

We made sure the same redirect_uri is configured in CallbackOptions and in authorizationParams. See the updated code below. We still get the same error for the App2 domain, but the default domain works fine. Do you think we are missing another configuration/variable?

import { initAuth0 } from '@auth0/nextjs-auth0';

export default (req?: { headers: { host: string } }) => {
  const isApp2 = req?.headers?.host.includes("App2 Domain");

if (isApp2) {
    return initAuth0({
      secret: process.env.AUTH0_SECRET_APP2,
      issuerBaseURL: process.env.AUTH0_ISSUER_BASE_URL_APP2,
      baseURL: process.env.AUTH0_BASE_URL_APP2,
      clientID: process.env.AUTH0_CLIENT_ID_APP2,
      clientSecret: process.env.AUTH0_CLIENT_SECRET_APP2,
      authorizationParams: {
        audience: process.env.AUTH0_AUDIENCE_APP2,
        redirect_uri: `${process.env.AUTH0_BASE_URL_APP2}api/auth/callback`,
      },
    });
  }

  return initAuth0({});
}
import { handleCallback } from '@auth0/nextjs-auth0';
import auth0 from '../../../src/utils/auth0.ts';

const afterCallback = async (req, res, session) => session;

export default (request, response) => auth0(request).handleAuth({
  async callback(req, res) {
    const isApp2 = req?.headers.host.includes("App2 Domain");
    const redirectUri = isApp2 ? process.env.AUTH0_BASE_URL_APP2 : process.env.AUTH0_BASE_URL;

    try {
      await handleCallback(req, res, { afterCallback, redirectUri: `${redirectUri}api/auth/callback` });
    } catch (error) {
      res.status(error.status).end(error.message);
    }
  },
})(request, response);

@adamjmcgrath
Copy link
Contributor

adamjmcgrath commented Mar 3, 2022

Hi @jagathwee - I can't see anything wrong with the code you've shared. It looks like the redirect_uri in the callback used for the code exchange should match the one in the login request. So I wouldn't expect you to get invalid_grant (Invalid authorization code) for that reason.

If you can share a running example I could probably debug it for you. Or, if you can share your tenant and clientID's I might be able to figure out what's going on from your tenant logs.

@jagathwee
Copy link
Author

Hi @adamjmcgrath,

Our tenant names have client information, so I can not share that in public. Could you please give me your email address to send you? Or I can even create an Auth0 support request if that helps.

Thanks

@adamjmcgrath
Copy link
Contributor

Or I can even create an Auth0 support request if that helps.

Yep - if you can create a support request, that would be great

@jagathwee
Copy link
Author

Done. I mentioned the link to this issue in the support request and provided tenants and clientIds involved.

@jagathwee
Copy link
Author

Hi @adamjmcgrath,

We did not use the domain-specific auth0 instance for the callback. That caused the authorization code exchange flow to communicate with the wrong tenant.

await handleCallback(req, res, { afterCallback, redirectUri: ${redirectUri}api/auth/callback });

should be:
await auth0(request).handleCallback(req, res, { afterCallback, redirectUri: ${redirectUri}api/auth/callback });

We could get both tenants to work on the same app with this fix. Thanks, @adamjmcgrath, and Supun from Auth0 support.

Best,
Jagath

@marcziss
Copy link

Hey @jagathwee, thanks for posting this! I am doing something similar, but need to do this for potentially 20-30 different apps. It's a multi tenant kind of application.
Question for you... not sure I understand exactly what's going on with auth0 under the covers, is initAuth0 getting called on every call for authentication, or does it just get called on the first call to authenticate per user?
Thanks in advance
Marc

@jagathwee
Copy link
Author

Hi @marcziss,

That's right, initAuth0() gets called on every call for auth. Otherwise, per-domain parameters are not applied. We thought about introducing a cache for Auth0<->Domain, but we did not try it yet.

Jagath

@mziss-wrberkley
Copy link

mziss-wrberkley commented Jun 14, 2022

Hey @jagathwee, appreciate the info. I'm trying to get a version of what your doing to work, but hitting a wall. Are you using the [...auth0].js file and just overriding the callback? I'm trying to adapt what you did to login so I can login to different domains but keep getting 404's

I'm doing something like

import auth0 from '../../tenants/bin.com/tenantAuth';

const lg = (request, response) => auth0(request).handleAuth({
    async login(req, res) {

      try {
        await auth0(request).handleLogin(req, res);
      } catch (error) {
        res.status(error.status).end(error.message);
      }
    },
  })(request, response);

export default lg;

and just choosing between 2 initAuth0's in the '../../tenants/bin.com/tenantAuth'; file.

Did you override login?

@jagathwee
Copy link
Author

Hi @marcziss,

Please ignore this if my response is too late. It looks like your approach is correct, but I am exactly not sure what you try to do with handeLogin(). The example I put in the comment might be helpful.

@mziss-wrberkley
Copy link

Thanks for getting back @jagathwee ! To answer my own question above I got it working by building an instance of initAuth0(currentTenantAuth) dynmically and then overriding the ...auth0].js file and implementing the auth functions like
auth/login.js like this


import getAuth from "../../../libs/currentTenantAuth";

export default async function login(req, res) {
  try {
        
    const auth = getAuth(req);
    await auth.handleLogin(req, res);
    
  } catch (error) {
    res.status(error.status || 400).end(error.message);
  }
}

and also implement similar functions: callback.js,logout.js, and me.js

@jagathwee
Copy link
Author

@marcziss, Glad to hear that!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

4 participants