How to set cookies using apollo server express

Viewed 587

I am using apollo server express on my backend and next js on frontend.

I have been trying to set cookies in backend using (response) from context but unfortunately it is not working. i would like your help.

here is my backend code.

import http from 'http';
import { ApolloServer } from 'apollo-server-express';
import express from 'express';
import cors from 'cors';
import { makeExecutableSchema } from '@graphql-tools/schema';
import { ApolloServerPluginDrainHttpServer } from 'apollo-server-core';
import { execute, subscribe } from 'graphql';
import {
    SubscriptionServer,
    ConnectionParams,
    ConnectionContext,
} from 'subscriptions-transport-ws';
import { connect } from './Config';
import { typeDefs } from './TypeDefs';
import { resolvers } from './Resolvers';
import { isAuthForSubscription } from './Helpers';
import cookieParser from 'cookie-parser';

const startServer = async () => {
    const app = express();

    app.use(
        cors({
            credentials: true,
            origin: 'http://localhost:3000',
        })
    );

    app.use(cookieParser());

    const httpServer = http.createServer(app);

    const subscriptionServer = SubscriptionServer.create(
        {
            schema: makeExecutableSchema({ typeDefs, resolvers }),
            execute,
            subscribe,
            onConnect: async (
                connectionParams: ConnectionParams,
                _websocket: any,
                context: ConnectionContext
            ) => {
                let user = null;
                if (connectionParams.Authorization) {
                    user = await isAuthForSubscription(connectionParams.Authorization);
                }
                return { context, user };
            },
        },
        {
            server: httpServer,
            path: '/graphql',
        }
    );

    const server = new ApolloServer({
        schema: makeExecutableSchema({ typeDefs, resolvers }),
        plugins: [
            ApolloServerPluginDrainHttpServer({ httpServer }),
            {
                serverWillStart: async () => {
                    return {
                        drainServer: async () => {
                            subscriptionServer.close();
                        },
                    };
                },
            },
        ],
        context: ({ req, res }) => ({ req, res }),
    });

    await server.start();

    server.applyMiddleware({ app });

    await new Promise<void>(resolve =>
        httpServer.listen({ port: 4000 }, resolve)
    );

    await connect();

    console.log(
        `server started on port http://localhost:4000${server.graphqlPath}`
    );

    return { server, app };
};
startServer();

// and my resolver is this one
import { ApolloError } from 'apollo-server-express';
import {
    TCreateAccountArgs,
    TLoginArgs,
    TContext,
    CookieName,
} from '../../__generated__';
import { generate } from '../../Helpers';
import { userModel } from '../../Models';
import { CookieOptions } from 'express';

export const login = async(_: any, args: TLoginArgs, { res, req }: TContext) => {
        try {
            const find = await userModel.findOne({ username: args.username });

            if (!find) {
                return new ApolloError('Account not found');
            }
            const comparePassword = generate.comparePassword(
                find.password,
                args.password
            );

            if (!comparePassword) {
                return new ApolloError('Incorrect password or username');
            }

            const generateToken = generate.generateToken({ _id: find._id });

            const cookieOptions: CookieOptions = {
                httpOnly: true,
                maxAge: 1 * 60 * 60 * 24 * 1000,
                secure: true
            };
            res.cookie(CookieName.token, generateToken, cookieOptions);

            return {
                token: generateToken,
                data: {
                    username: find.username,
                    _id: find._id,
                    email: find.email,
                    profilePicture: find.profilePicture,
                    createdAt: find.createdAt,
                    updatedAt: find.updatedAt,
                },
            };
        } catch (error: any) {
            return new ApolloError(
                `Unable to login due to internal server error ${error.message}`
            );
        }
    };


on frontend I am receiving this error message. Cannot read property 'cookie' of undefined

1 Answers

This question has been there from several months ago.

Just in case you haven't been able to fix it yet, the reason why you're not seeing the cookies in the frontend is that you're using the option httpOnly, those cookies are not supposed to be readable by the browser (they are useful to handle authentication in the server while protecting you from cross site scripting).

If you really need to read these cookies in the browser, you should set the httpOnly option to false.

Related