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

Error: Cookie length will exceed browser maximum. Length: number #37

Open
aayestashn opened this issue Jun 2, 2023 · 0 comments
Open

Comments

@aayestashn
Copy link

Describe the bug

As a user, I am receiving the email with the magic link, but production gave me the following error message after submitting the form with the email.

Error: Cookie length will exceed browser maximum. Length: 4503

after calling the function:

  await auth.authenticate("email-link", request, {
    successRedirect: "/auth/login",
    // If this is not set, any error will be throw and the ErrorBoundary will be
    // rendered.
    failureRedirect: "/auth/login",
  });

This is the track trace:

The throw new Error("Cookie length will exceed browser maximum. Length: " + serializedCookie.length); method in the remix createCookieSessionStorageFactory function

/**
 * Creates and returns a SessionStorage object that stores all session data
 * directly in the session cookie itself.
 *
 * This has the advantage that no database or other backend services are
 * needed, and can help to simplify some load-balanced scenarios. However, it
 * also has the limitation that serialized session data may not exceed the
 * browser's maximum cookie size. Trade-offs!
 *
 * @see https://remix.run/utils/sessions#createcookiesessionstorage
 */
const createCookieSessionStorageFactory = createCookie => ({
  cookie: cookieArg
} = {}) => {
  let cookie = cookies.isCookie(cookieArg) ? cookieArg : createCookie((cookieArg === null || cookieArg === void 0 ? void 0 : cookieArg.name) || "__session", cookieArg);
  sessions.warnOnceAboutSigningSessionCookie(cookie);
  return {
    async getSession(cookieHeader, options) {
      return sessions.createSession(cookieHeader && (await cookie.parse(cookieHeader, options)) || {});
    },
    async commitSession(session, options) {
      let serializedCookie = await cookie.serialize(session.data, options);
      if (serializedCookie.length > 4096) {
        throw new Error("Cookie length will exceed browser maximum. Length: " + serializedCookie.length);
      }
      return serializedCookie;
    },
    async destroySession(_session, options) {
      return cookie.serialize("", {
        ...options,
        expires: new Date(0)
      });
    }
  };
};

In the function of the library authenticate and in the line const cookie = await sessionStorage.commitSession(session);

    async authenticate(request, sessionStorage, options) {
        var _a;
        const session = await sessionStorage.getSession(request.headers.get('Cookie'));
        const form = new URLSearchParams(await request.text());
        // This should only be called in an action if it's used to start the login process
        if (request.method === 'POST') {
            if (!options.successRedirect) {
                throw new Error('Missing successRedirect. The successRedirect is required for POST requests.');
            }
            // get the email address from the request body
            const emailAddress = form.get(this.emailField);
            // if it doesn't have an email address,
            if (!emailAddress || typeof emailAddress !== 'string') {
                const message = 'Missing email address.';
                if (!options.failureRedirect) {
                    throw new Error(message);
                }
                session.flash(this.sessionErrorKey, { message });
                const cookie = await sessionStorage.commitSession(session);
                throw (0, server_runtime_1.redirect)(options.failureRedirect, {
                    headers: { 'Set-Cookie': cookie },
                });
            }
            try {
                // Validate the email address
                await this.validateEmail(emailAddress);
                const domainUrl = this.getDomainURL(request);
                const magicLink = await this.sendToken(emailAddress, domainUrl, form);
                session.set(this.sessionMagicLinkKey, await this.encrypt(magicLink));
                session.set(this.sessionEmailKey, emailAddress);
                throw (0, server_runtime_1.redirect)(options.successRedirect, {
                    headers: {
                        'Set-Cookie': await sessionStorage.commitSession(session),
                    },
                });
            }
            catch (error) {
                // eslint-disable-next-line @typescript-eslint/no-explicit-any
                if (error.status === 302) {
                    // If it's a redirect, then just throw the redirect as it is
                    throw error;
                }
                if (!options.failureRedirect) {
                    throw error;
                }
                const { message } = error;
                session.flash(this.sessionErrorKey, { message });
                const cookie = await sessionStorage.commitSession(session);
                throw (0, server_runtime_1.redirect)(options.failureRedirect, {
                    headers: { 'Set-Cookie': cookie },
                });
            }
        }
        let user;
        try {
            // If we get here, the user clicked on the magic link inside email
            const magicLink = (_a = session.get(this.sessionMagicLinkKey)) !== null && _a !== void 0 ? _a : '';
            const { emailAddress: email, form } = await this.validateMagicLink(request.url, await this.decrypt(magicLink));
            // now that we have the user email we can call verify to get the user
            user = await this.verify({ email, form, magicLinkVerify: true });
        }
        catch (error) {
            // if something happens, we should redirect to the failureRedirect
            // and flash the error message, or just throw the error if failureRedirect
            // is not defined
            if (!options.failureRedirect) {
                throw error;
            }
            const { message } = error;
            session.flash(this.sessionErrorKey, { message });
            const cookie = await sessionStorage.commitSession(session);
            throw (0, server_runtime_1.redirect)(options.failureRedirect, {
                headers: { 'Set-Cookie': cookie },
            });
        }
        if (!options.successRedirect) {
            return user;
        }
        // remove the magic link and email from the session
        session.unset(this.sessionMagicLinkKey);
        session.unset(this.sessionEmailKey);
        session.set(options.sessionKey, user);
        const cookie = await sessionStorage.commitSession(session);
        throw (0, server_runtime_1.redirect)(options.successRedirect, {
            headers: { 'Set-Cookie': cookie },
        });
    }

Is any way to print all the values of the session to check if for some reason I am putting external data?

Your Example Website or App

https://aa8d-190-135-204-71.ngrok-free.app/auth/login

Steps to Reproduce the Bug or Issue

  1. Using the library fill the email, and then trigger the authentication process.

Expected behavior

As a user, I am receiving the email with the magic link, but production gave me the following error message after submitting the form with the email.
Error: Cookie length will exceed browser maximum. Length: 4503

Screenshots or Videos

Screenshot 2023-06-02 at 5 21 36 PM Screenshot 2023-06-02 at 5 21 43 PM

Platform

  • OS: [macOS]
  • Browser: [Chrome, Safari]
  • Version: [113.0,16.5]

Additional context

No response

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

No branches or pull requests

1 participant