Why are cookies not sent to the server via getServerSideProps in Next.js?
Asked Answered
T

2

23

Cookies are not sent to the server via getServerSideProps, here is the code in the front-end:

export async function getServerSideProps() {
  const res = await axios.get("http://localhost:5000/api/auth", {withCredentials: true});
  const data = await res.data;
  return { props: { data } }
}

On the server I have a strategy that checks the access JWT token.

export class JwtStrategy extends PassportStrategy(Strategy, "jwt") {
    constructor() {
        super({
            ignoreExpiration: false,
            secretOrKey: "secret",
            jwtFromRequest: ExtractJwt.fromExtractors([
                (request: Request) => {
                    console.log(request.cookies) // [Object: null prototype] {}
                    let data = request.cookies['access'];
                    return data;
                }
            ]),
        });
    }

    async validate(payload: any){
        return payload;
    }
}

That is, when I send a request via getServerSideProps cookies do not come to the server, although if I send, for example via useEffect, then cookies come normally.

Timelag answered 4/9, 2021 at 16:48 Comment(7)
getServerSideProps get a ctx argument which has req, and res, refer here , you can use nookies library to parse the cookiesBriant
@SachinAnanthakumar, could you show me please how this is done with my code example?Rubenstein
refer to thisBriant
@SachinAnanthakumar also getting [Object: null prototype] {} on server :(Rubenstein
@ОвовОчоы You need to explicitly pass the cookies from getServerSideProps context to the axios request. If you tried that and it's still not working can you show us how you're doing it?Schiller
@Schiller please tell me how can i explicitly pass cookie through axios?Rubenstein
I have got a similar problem, but in the opposite direction. When I set a cookie from my seperate Node.js environment, the fetch called inside getServerSideProps() does not set cookies in the browser too. I understand why cookies are not being passed to the server, but I cannot get why they are not set from the server to the frontendKelter
S
51

That's because the request inside getServerSideProps doesn't run in the browser - where cookies are automatically sent on every request - but actually gets executed on the server, in a Node.js environment.

This means you need to explicitly pass the cookies to the axios request to send them through.

export async function getServerSideProps({ req }) {
    const res = await axios.get("http://localhost:5000/api/auth", {
        withCredentials: true,
        headers: {
            Cookie: req.headers.cookie
        }
    });
    const data = await res.data;
    return { props: { data } }
}

The same principle applies to requests made from API routes to external APIs, cookies need to be explicitly passed as well.

export default function handler(req, res) {
    const res = await axios.get("http://localhost:5000/api/auth", {
        withCredentials: true,
        headers: {
            Cookie: req.headers.cookie
        }
    });
    const data = await res.data;
    res.status(200).json(data)
}
Schiller answered 4/9, 2021 at 18:46 Comment(10)
thanks mate. this helps to resolve issue on nextjs + lumen api based app.Scimitar
Did not work... srcshare.io/?id=6246c6b123709353aaa1a350 @SchillerAuxochrome
@OzanKurt It's not clear from the link you posted what's not working. I'd recommend you create a new question describing in detail the issue you're having.Schiller
@Schiller what would you recommend to avoid settings header for every request? Is it possible to do that in axios interceptor?Vories
@LouayHamada I'm not entirely sure you could use an axios interceptor as you'd need access to the req object to set the cookies. However, you could create a wrapper around axios itself that would add the additional cookies logic.Schiller
@Schiller I didn't get the idea of creating wrapper around axios, can you please provide an example?Vories
@LouayHamada Like an abstraction where you'd pass req and it would call and pass the cookies to the axios request.Schiller
I find it quite annoying though. Having to manually retrieve the cookie and pass it in each request like that is a big loss of energy. What if I have 600 server rendered pages ?Respectful
@Respectful There's no way around it, the cookies need to be explicitly set when making a request from the server. You could create an abstraction to do it on every request.Schiller
Is it safe to pass the cookies like this?Toupee
O
3

Explanation:

In Next.js, cookies are not automatically sent to the server via data fetching methods like getServerSideProps because these methods are executed on the server-side, and cookies are stored on the client-side. This means that if you're making a request from getServerSideProps, it will not have access to the client's cookies by default, and the request will be sent with an empty cookie.

Although, we can set the client's cookies in getServerSideProps by extracting them from the incoming request headers. Whenever a user requests a page from the browser, the request is sent to the frontend server where the Next.js application is running. The server then builds the initial HTML and executes getServerSideProps. At this point, Next.js inject context parameter to getServerSideProps that contains information about the incoming request, including the request object, response object, query parameters, and more. We can access the browser request headers and extract the cookies from there. Once we have the cookies, we can set them explicitly in any further request made from getServerSideProps.

export async function getServerSideProps(context) {
    const {req} = context;
    const res = await axios.get("http://localhost:5000/api/auth", {
        withCredentials: true,
        headers: {
            Cookie: req.headers.cookie //like this
        }
    });
    const data = await res.data;
    return { props: { data } }
}
Oldline answered 18/3, 2023 at 8:53 Comment(1)
In my case, i can clearly see the correct cookie is attached to the javascript bundles for the particular route (_app.js, index.js, etc), but when I attempt to access it via req.cookies or req.headers.cookie in my [route]/index.tsx's getServerSideProps, I pull a blank. getServerSideProps only seems to get the cookie when navigating from another page on the client-side (.e.g from / to/app). How is this possible?Earing

© 2022 - 2024 — McMap. All rights reserved.