0

I have a Next.js application where authentication is set up with the Auth0 Next.js SDK.

Currently the AUTH0_CLIENT_SECRET is being set as an environment variable when deploying.

I would like to use Google Cloud Secret Manager to get the AUTH0_CLIENT_SECRET during runtime and set it using the initAuth0 method.

I'm following this example: https://github.com/auth0/nextjs-auth0/blob/main/EXAMPLES.md#create-your-own-instance-of-the-sdk

But I can't figure out how I can await the response from secret manager when I need to have the secret ready for calling the method initAuth0({clientSecret...}) and I need that in place to setup the auth end points with auth0.handleAuth().

This is my attempt: /pages/api/auth/[...auth].ts

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

const asyncHandleAuth = async () => {
  const clientSecret = await getSecret("AUTH0_CLIENT_SECRET");

  const auth0 = initAuth0({ 
    clientSecret // The rest of the config is set with environment variables
  }); 

  return auth0.handleAuth();
};

export default asyncHandleAuth();
jccampanero
  • 50,989
  • 3
  • 20
  • 49
  • Sorry, because I am probably missing something, but with the code you posted, `const clientSecret = await getSecret("AUTH0_CLIENT_SECRET");`, you are already waiting until the secret is returned; your code will suspend on that line until `getSecret` terminates. As a consequence, the secret should be ready when using the `initAuth0` function. Is it not the case? Are you facing any problem? – jccampanero May 17 '22 at 21:56
  • Hi @jccampanero. I can start the web server without any errors but when I open the website in the browser and it makes requests to api/auth/me and api/auth/login they both return 500 and the terminal shows `TypeError: resolver is not a function`. So I guess wrapping the handleAuth0 method in an async function is not possible, but I don't know what I can do instead. – Jens Ravn Jensen May 18 '22 at 16:19
  • Thank you for the feedback @JensRavnJensen. According to the error, I posted a possible solution. I hope it helps. – jccampanero May 18 '22 at 18:12

2 Answers2

1

In the code you posted in your answer:

const clientSecret = await getSecret("AUTH0_CLIENT_SECRET");

you are already waiting until the secret is returned: your code will suspend on that line until getSecret ends. As a consequence, the secret should be ready when using the initAuth0 function.

Perhaps, and according to your comments, the problem could be motivated by your export. You are exporting the asyncHandleAuth function like this:

export default asyncHandleAuth();

But I think it should be instead:

export default asyncHandleAuth;

Your answer makes perfect sense: the actual problem is that you need to provide the appropriate arguments, the request and response representations, to your handler function to perform the actual invocation. But please, be aware that the proposed export default still is valid, in your code you are executing a function that returns the thing that is being exported. Probably you could simplify it like this:

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

const asyncHandleAuth = async (req: NextApiRequest, res: NextApiResponse) => {
  const clientSecret = await getSecret("AUTH0_CLIENT_SECRET");

  const auth0 = initAuth0({ 
    clientSecret // The rest of the config is set with environment variables
  }); 

  return auth0.handleAuth()(req, res);
};

export default asyncHandleAuth;

Note that there is no need for the first arrow function.

jccampanero
  • 50,989
  • 3
  • 20
  • 49
  • Hi @jccampanero. Thank you for the suggestion. I was actually also thinking about this. But if I try with `export default asyncHandleAuth` the end point never returns a response and I get the following message in the terminal `API resolved without sending a response for /api/auth/me, this may result in stalled requests.` – Jens Ravn Jensen May 18 '22 at 18:59
  • Thank you very much for the feedback Jens. I realized your answer and the way you need to use the function, and the arguments males perfect sense. I updated my answer to give you a possible simplification of your code. – jccampanero May 18 '22 at 21:21
1

After some hair pulling I found the problem. Next.js expects the export default function to be of type NextApiHandler but I was returning Promise<NextApiHandler>. I solved it by wrapping it in another function that takes the request and response arguments and use them to call handleAuth before returning it.

This worked for me:

const asyncHandleAuth =
  () => async (req: NextApiRequest, res: NextApiResponse) => {
    const clientSecret = await getSecret("AUTH0_CLIENT_SECRET");

    const auth0 = initAuth0({
      clientSecret, // The rest of the config is set with environment variables
    });
    
    return auth0.handleAuth()(req, res);
  };

export default asyncHandleAuth();