CloudFront responds with 413 after AWS Cognito redirect

939 Views Asked by At

I have a React app built using Serverless NextJS and served behind AWS CloudFront. I am also using AWS Cognito to do authentication of our users.

After a user successfully authenticates through AWS Cognito, they are redirected to my React App with a query string containing OAuth tokens (id_token, access_token, refresh_token, raw[id_token], raw[access_token], raw[refresh_token], raw[expires_in], raw[token_type]).

It seems that the query string is simply larger than AWS CloudFront's limits and it is throwing the following error below:

413 ERROR
The request could not be satisfied.

Bad request. We can't connect to the server for this app...

Generated by cloudfront (CloudFront)
Request ID: FlfDp8raw80pAFCvu3g7VEb_IRYbhHoHBkOEQxYyOTWMsNlRjTA7FQ==

This error has been encountered before by many other users (see example). Keen to know:

  • Are there any workarounds? Perhaps is there a way to configure AWS Cognito to reduce the number of tokens that it is passing in the query string by default?

  • Is it possible to configure AWS CloudFront to ignore enforcing its default limits on certain pages (and not cache theme)?

  • What's the suggestion going forward? The only thing I can imagine is not to use AWS CloudFront.

1

There are 1 best solutions below

1
On

After analysing the query fields that AWS Cognito sends to a callback URL, I was able to determine that not all fields are required for my usecase. Particularly the raw OAuth token fields.

With that information, I solved the problem by writing a "middleware" to intercept my backend system redirecting to my frontend (that is sitting behind CloudFront) and trimming away query string fields that I do not need to complete authentication.

In case this could inspire someone else stuck with a similar problem, here is what my middleware looks like for my backend system (Strapi):

module.exports = (strapi) => {
  return {
    initialize() {
      strapi.app.use(async (ctx, next) => {
        await next();

        if (ctx.request.url.startsWith("/connect/cognito/callback?code=")) {
          // Parse URL (with OAuth query string) Strapi is redirecting to
          const location = ctx.response.header.location;
          const { protocol, host, pathname, query } = url.parse(location);

          // Parse OAuth query string and remove redundant (and bloated) `raw` fields
          const queryObject = qs.parse(query);
          const trimmedQueryObject = _.omit(queryObject, "raw");

          // Reconstruct original redirect Url with shortened query string params
          const newLocation = `${protocol}//${host}${pathname}?${qs.stringify(
            trimmedQueryObject
          )}`;

          ctx.redirect(newLocation);
        }
      });
    },
  };
};