Skip to content

Cookie Headers Not Forwarded Correctly in React Router and Backend Integration #10488

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

Closed
sidyr6002 opened this issue Feb 20, 2025 · 1 comment

Comments

@sidyr6002
Copy link

sidyr6002 commented Feb 20, 2025

Reproduction

You can access the backend code: https://github.com/sidyr6002/chat-app-backend,
frontend code: https://github.com/sidyr6002/chat-app-frontend

Frontend Setup

  1. Create an .env file with the following content:
    BACKEND_URL=http://localhost:3000
    SESSION_SECRET=edb906c05d1aa272eca98019cbf637bf9983c043c02b00a5c7a0df5e041b0447
  2. Run the following commands:
    pnpm install
    pnpm dev

Backend Setup

  1. Set up the database:
    cd /database
    docker compose up
  2. Create an .env file with the following content:
    DATABASE_URL="postgres://user:password@localhost:5432/chatapp?schema=public"
    JWT_SECRET=string
    JWT_REFRESH_SECRET=string
    JWT_EXPIRATION="15m"
  3. Run the following commands:
    pnpm install
    pnpm start:dev

System Info

System:
    OS: Linux 6.11 Ubuntu 24.04.2 LTS 24.04.2 LTS (Noble Numbat)
    CPU: (8) x64 Intel(R) Core(TM) i5-8265U CPU @ 1.60GHz
    Memory: 1.37 GB / 7.61 GB
    Container: Yes
    Shell: 5.2.21 - /usr/bin/bash
  Binaries:
    Node: 20.15.1 - ~/.nvm/versions/node/v20.15.1/bin/node
    Yarn: 1.22.22 - ~/.nvm/versions/node/v20.15.1/bin/yarn
    npm: 10.8.2 - ~/.nvm/versions/node/v20.15.1/bin/npm
    pnpm: 9.15.3 - ~/.local/share/pnpm/pnpm
    bun: 1.1.10 - ~/.local/share/reflex/bun/bin/bun
  Browsers:
    Chrome: 133.0.6943.98

Used Package Manager

pnpm

Expected Behavior

The headers set in the backend should be reflected in the browser. The backend sets cookies (myRefreshToken and accessToken) during the sign-in process.

Backend Code (NestJS):

@ApiOkResponse({ type: AccessTokenDto })
@Post('signin')
async login(
    @Body() signInDto: SingInDto,
    @Res({ passthrough: true }) res: Response,
): Promise<AccessTokenDto> {
    const { accessToken, refreshToken } = await this.authService.signIn(
        signInDto.email,
        signInDto.password,
    );
    res.cookie('myRefreshToken', refreshToken, {
        httpOnly: true,
        secure: false,
        sameSite: 'lax',
        maxAge: 7 * 24 * 60 * 60 * 1000,
    });
    return { accessToken };
}

Frontend Code (React Router Action):

export const action: ActionFunction = async ({ request }) => {
    const formData = await request.formData();
    const email = formData.get('email');
    const password = formData.get('password');
    const validation = signInSchema.safeParse({
        email,
        password,
    });
    if (!validation.success) {
        return Response.json(
            { errors: validation.error.format() },
            { status: 400 }
        );
    }
    try {
        const backendUrl = process.env.BACKEND_URL || '';
        const response = await axios.post(
            `${backendUrl}/auth/signin`,
            { email, password },
            {
                headers: { 'Content-Type': 'application/json' },
                withCredentials: true,
            }
        );
        const { accessToken } = response.data;
        console.log("accessToken", accessToken);
        console.log('Response headers:', response.headers);

        const session = await getSession(request.headers.get('Cookie'));
        session.set('accessToken', accessToken);
        const sessionCookie = await commitSession(session);

        return redirect("/", {
            headers: {
                "Set-Cookie": sessionCookie,
            },
        });
    } catch (error) {
        console.error('Sign-in error:', error);
        return Response.json(
            { error: "Invalid credentials or server error." },
            { status: 401 }
        );
    }
};

The signin API sets the myRefreshToken cookie in the backend and sends the accessToken to the frontend. Both cookies should appear in the browser.

Actual Behavior

Only one cookie (accessToken) is being set in the browser. The myRefreshToken cookie, which is set by the backend, does not appear in the browser.

Upon inspecting the network request in the browser's developer tools, the response headers from the backend include both cookies:

Set-Cookie: myRefreshToken=...; HttpOnly; Path=/; SameSite=Lax; Max-Age=604800
Set-Cookie: accessToken=...; Path=/; HttpOnly

However, in the browser's "Application" tab, only the accessToken cookie is visible.

Image

Additional Information

  • The withCredentials: true option is set in the Axios request.
  • The backend's CORS configuration allows credentials.
  • The SameSite attribute for the myRefreshToken cookie is set to lax.

Observation:

The response headers returned by the backend during the sign-in process contain the myRefreshToken cookies, as confirmed by logging console.log('Response headers:', response.headers);. While the headers appear correct in the network response and logs, the myRefreshToken cookie is not being set in the browser, even though it is present in the Set-Cookie header of the response.

Copy link
Contributor

Thank you for opening this issue, and our apologies we haven't gotten around to it yet!

With the release of React Router v7 we are sun-setting continued development/maintenance on Remix v2. If you have not already upgraded to React Router v7, we recommend you do so. We've tried to make the upgrade process as smooth as possible with our Future Flags. We are now in the process of cleaning up outdated issues and pull requests to improve the overall hygiene of our repositories.

We plan to continue to address 2 types of issues in Remix v2:

  • Bugs that pose security concerns
  • Bugs that prevent upgrading to React Router v7

If you believe this issue meets one of those criteria, please respond or create a new issue.

For all other issues, ongoing maintenance will be happening in React Router v7, so:

  • If this is a bug, please reopen this issue in that repo with a new minimal reproduction against v7
  • If this is a feature request, please open a new Proposal Discussion in React Router, and if it gets enough community support it can be considered for implementation

If you have any questions you can always reach out on Discord. Thanks again for providing feedback and helping us make our framework even better!

@github-actions github-actions bot closed this as not planned Won't fix, can't repro, duplicate, stale May 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant