A module for adding cookie support for both Fastify and Express adapters for NestJS. There's a bit of magic that goes on under the hood when it comes to binding the cookie parser, but this module uses nothing except for what Nest itself provides, meaning no extra middleware, no extra functions, just plain, simple code. Depending on if the Fastify adapter is being used or the Express one, a request hook is added or a middleware is setup. This is for parsing incoming cookies from the Cookie
header to make them available. And unlike using Nest middleware on the Fastify Adapter, by using a request hook we are able to keep the req.cookies
on the top level regardless of the adapter. 🎆
As of Nest version 7.5.3, @Res()
can now take in a parameter of { passthrough: true }
which will allow Nest to still handle sending the response, while allows devs to use @Res()
to get the response object so that cookies and headers can be set. This means cookie middleware that already works for Express and Fastify work for Nest in the same way. You can read more about it on Nest's docs site.
To install the package, use your package manager of choice and install nest-cookies
E.g.
npm i nest-cookies
yarn add nest-cookies
pnpm i nest-cookies
To make sure that the request hook/middleware is bound, make sure to import the CookieModule
in your root module. The earlier you import the module, the sooner the middleware runs (after middleware defined in your root module, according to the documentation). There is also an exported interceptor for setting cookies, the CookiesInterceptor
. This can be used as any other interceptor, and is described in more detail later in the doc.
There is a base cookie interceptor that exists for the purpose of setting the response cookie. It reads these cookies from req._cookies
which is instantiated in the middleware/request hook. If you need to read the cookie from a different context, like GraphQL, you can extend
the CookiesInterceptor
and override the getRequestResponse
method
@Injectable()
export class GqlCookieInterceptor extends CookiesInterceptor {
getRequestResponse(context: ExecutionContext) {
const gql = GqlExecutionContext.create(context);
return {
req: gql.getContext().req,
res: gql.getContext().res,
};
}
}
and now cookies will be set properly for GQL requests as well. Similarly, in resovlers you can modify the req._cookies
property by using @Context() ctx
and ctx.req._cookies
.
You can also modify the interceptor's getRequestResponse
method to use the proper req
and res
depending on the request type, if you have a hybrid server serving both HTTP and GQL requests.
To set a cookie, a cookie object simply needs to be added to the req._cookies
array. This cookie should be an object with a name
and value
property and with an optional options
property with an object that has the following properties to it:
Key | Type | Description |
---|---|---|
expires | Date | The date for the cookie to expire. If maxAge is also set, maxAge will be taken to be the proper value |
maxAge | Number | the maximum age in seconds the cookie should live |
domain | String | The host which the cookie should be sent to |
path | String | The path that the cookie should be sent to |
secure | Boolean | If the cookie should be set as Secure. If this is true, the request must be used over HTTPS |
httpOnly | Boolean | If the cookie should be only accessible via HTTP request. Setting this to true forbids the cookie from being read via Document.cookie |
sameSite | 'Strict', 'Lax' or 'None' | Asserts that a cookie must not be sent with cross-origin requests, providing some protection against cross-site request forgery attacks |
For more information about cookie options, visit the MDN documentation.
Cookies that are sent to the server are populated on the req.cookies
property, and are in the form of an object. The req.cookies
will have keys that match the name of the sent cookies, and the values will be the values of the cookies, represented as strings.
E.g. If a request is sent with the header Cookie: sessionid=54
then req.cookies
will have
{
sessionid: '54';
}
Unlike the popular cookie-parser, this package does not handle the signing of cookies. Generally, if a cookie is random enough signing a cookie is not absolutely necessary. However, there is mention in the cookie RFC about how to keep a session cookie secure. It is advised to follow the advice found there if security is a concern (and it should be).