Using apollo-server-express, express-session and socketio – Cors issue present when socketio tries to connect on the client side

I am trying to use apollo-server-express to maintain a graphql endpoint and other endpoints to perform oAuth with twitter. I wanted to perform the oauth in the client in a way that a browser tab opens and a socket transmits a "MESSAGE" (as an example) from the callback to the server back to the main client window.

Here’s my index.js

import { ApolloServer } from "apollo-server-express";
import {
  ApolloServerPluginDrainHttpServer,
  ApolloServerPluginLandingPageLocalDefault,
} from "apollo-server-core";
import express from "express";
import session, { Session } from "express-session";
import crypto from "crypto";
import cors from "cors";
import http from "http";
import dotenv from "dotenv";
const socketio = require("socket.io");

dotenv.config();

import { twitterAuthClient, TWITTER_STATE } from "./utils/twitter";
import { schema } from "./schema";
import { prisma } from "./graphql/context";

declare module "express-serve-static-core" {
  interface Request {
    session: Session & {
      socketId: string;
    };
  }
}

(async () => {
  const app: express.Express = express();

  const httpServer = http.createServer(app);
  const io = socketio(httpServer);
  app.use(express.json());
  app.use(
    session({
      secret: [crypto.randomBytes(32).toString("hex")],
      resave: true,
      saveUninitialized: true,
    })
  );

  const plugins = [ApolloServerPluginDrainHttpServer({ httpServer })];
  plugins.push(ApolloServerPluginLandingPageLocalDefault());

  const server = new ApolloServer({
    plugins,
    schema,
    context: ({ req }) => {
      console.log(req.session);
      return {
        req,
        prisma,
      };
    },
    introspection: true, // disable in Prod
  });

  await server.start();

  const corsOptions = {
    origin: "http://localhost:3000",
  };

  server.applyMiddleware({
    app,
    cors: corsOptions,
  });

  // This custom middleware picks off the socket id (that was put on req.query)
  // and stores it in the session so we can send back the right info to the
  // right socket
  const addSocketIdToSession = (req: any, res: any, next: any) => {
    req.session.socketId = req.query.socketId;

    console.log(req.session.socketId);
    next();
  };

  app.get("/", async (_, res) => {
    res.send("Example Server");
  });

  app.get("/login", addSocketIdToSession, async (req, res) => {
    const authUrl = twitterAuthClient.generateAuthURL({
      state: TWITTER_STATE,
      code_challenge_method: "s256",
    });

    res.redirect(authUrl);
  });

  app.get("/callback", async (req, res) => {
    try {
      const { code, state } = req.query;
      if (state !== TWITTER_STATE)
        return res.status(500).send("State isn't matching");
      await twitterAuthClient.requestAccessToken(code as string);

      io.in(req.session.socketId).emit("user", "MESSAGE");

      res.end();
    } catch (error) {
      console.log(error);
    }
  });

  const port = process.env.PORT || 4000;

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

  console.log(`Server ready at port: ${port} and path: ${server.graphqlPath}`);
})();

And on the client side I am using in my App.js in React

import io from "socket.io-client";

const API_URL = "http://127.0.0.1:4000";
const socket = io(API_URL);

But an issue persists, even though I am applying core options with applyMiddleware in apollo-server

Access to XMLHttpRequest at 'http://127.0.0.1:4000/socket.io/?EIO=3&transport=polling&t=O5gzz1z' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

On server side I am using

"apollo-server-express": "^3.9.0",
"express-session": "^1.17.3",
"socket.io": "^4.5.1",

On client side

"socket.io-client": "^4.5.1"

Any clues are appreciated. Thanks

>Solution :

It looks like you need to enable CORS for socket.io in order for it to work when using a different domain (and port).

Take a look at:
https://socket.io/docs/v4/handling-cors/ for more information about how to handle Socket.IO CORS

Leave a Reply