panva / openid-client

OAuth 2 / OpenID Connect Client API for JavaScript Runtimes
MIT License
1.83k stars 392 forks source link

Timeout error on Issuer.discover with AppEngine hosted #479

Closed MSchiellerup closed 2 years ago

MSchiellerup commented 2 years ago

Describe the bug I'm using this OIDC package for handling governmental authorized authentication and it works like a charm in development env. I use tsc to being able to run it with Node on Google AppEngine. When the server is live, and it users the Issuer.discover on the authority url, it times out and exits the container.

So short - when a deployed node server uses Issuer.discover(AUTHORITY_URL) it times out after 3500ms.

To Reproduce This is the helperFunction to initialize and retrieve the issuer and client

const CLIENT_SECRET = process.env.OIDC_CLIENT_SECRET || "";
const CLIENT_ID = process.env.OIDC_CLIENT_ID || "";
const REDIRECT_URI = process.env.OIDC_REDIRECT_URI || "";
const AUTHORITY_URI = process.env.OIDC_AUTHORITY_URI || "";
const RESPONSE_TYPE = "code";

var brokerIssuer: Issuer<BaseClient> | null = null;
var client: BaseClient | null = null;

export const getOIDC = async () => {
  if (!brokerIssuer) {
    brokerIssuer = await Issuer.discover(AUTHORITY_URI);
    client = new brokerIssuer.Client({
      client_id: CLIENT_ID,
      client_secret: CLIENT_SECRET,
      redirect_uris: [REDIRECT_URI],
      response_types: [RESPONSE_TYPE],
    });
  }
  return { brokerIssuer, client };
};

This is how it's called on server startup

(async () => {
  const { brokerIssuer } = await getOIDC();
  console.log("Broker issuer from:", brokerIssuer.metadata.issuer);
  app.listen(process.env.PORT || 8080, () => {
    console.log(`🚀 Server running on port`, process.env.PORT || 8080);
  });
})();`

And this is how my login route (Just to retrieve the authorizationUrl)

router.post("/login", async function (req: Request, res: Response) {
  try {
    const { client } = await getOIDC();
    if (!client) throw new Error("Client could not be authorized");
    const { user, type }: { user: User; type: string } = req.body;
    if (user === undefined || type === undefined) throw new Error("data not provided")
    const state = pushNewUserToStore(user, type);
    if (nonce === undefined) nonce = generators.nonce();
    const brokerUrl = client.authorizationUrl({
      scope: "openid nemid mitid",
      state,
      nonce,
    });
    res.status(200).send(brokerUrl);
  } catch (err: any) {
    res.status(500).send({ name: err.name, message: err.message });
  }
});

Error from AppEngine logs

/layers/google.nodejs.yarn/yarn_modules/node_modules/openid-client/lib/helpers/request.js:136

throw new RPError(outgoing request timed out after ${opts.timeout}ms); ^

RPError: outgoing request timed out after 3500ms
at /layers/google.nodejs.yarn/yarn_modules/node_modules/openid-client/lib/helpers/request.js:136:13
at async Function.discover (/layers/google.nodejs.yarn/yarn_modules/node_modules/openid-client/lib/issuer.js:171:22)
[start] 2022/03/23 15:51:43.184932 Start program failed: failed to detect app after start: ForAppStart(): [aborted, context canceled. subject:"app/invalid" Timeout:30m0s, attempts:949 aborted, context canceled. subject:"app/valid" Timeout:30m0s, attempts:949]
Container called exit(1)

Expected behaviour It was expected that on server startup, it would retrieve the Issuer.discover to generate the Client so this always was accessible when a call was made with regards to the OIDC client. If the request was made to /login it would send maker the brokerURL to redirect on the website, and handle the Callback later on.

But it never gets past the initialization of the discover.

Environment:

Hope the prodived info is enough and that you can help me out of this pickle :-)

panva commented 2 years ago

Hi @MSchiellerup you can configure the timeout durations. Other than that I cannot in any way, shape or form help you debug a networking issue.