ssaavvaa
ssaavvaa

Reputation: 19

Apollo server subscription middleware

i pass currentuser auth to app middlware and it works just fine... but when i run subscription in graphql its saying current user not found.... what i am doing wrong guys ? when i remove just currentuser from apollo server it works...i was trying to follow docs from apollo website to create this

ive tried move logic to the body of apollo server but it didnt work out for some reason

const express = require('express');
const mongoose = require('mongoose');
const jwt = require('jsonwebtoken');
const cors = require('cors');
require('dotenv').config({ path: 'variables.env' });
const app = express();
const { createServer } = require('http');

const corsOptions = {
    origin:'http://localhost:8000',
    credentials:true
};

mongoose.set('useFindAndModify', false);

app.use(cors(corsOptions));

app.use(async (req , res , next) => {
    const token = req.headers["authorization"];
    if(token !== "null"){
      try{
          const currentUser = await jwt.verify(token, process.env.SECRET);
          req.currentUser = currentUser;
          console.log(currentUser)

      }catch(err){
          console.log(err)
      }
    }
    next();
})


const Event = require('./models/Event');
const User = require('./models/User');
const Message = require('./models/Messages');

const { ApolloServer } = require('apollo-server-express');

const { typeDefs } = require('./Schema');
const { resolvers } = require('./Resolvers');


mongoose
  .connect(process.env.MONGO_URI, {useNewUrlParser: true , useCreateIndex: true})
  .then(() => console.log('DB connected'))
  .catch(err => console.error(err))


  const SERVER = new ApolloServer({
    typeDefs,
    resolvers,
    context: ({req, res}) => ({
         Event,
         User,
         Message,
         currentUser:req.currentUser
      }),

    playground: {
      settings: {
        'editor.theme': 'dark'
      }
    }
  });

SERVER.applyMiddleware({ app , path:'/graphql' });

const httpServer = createServer(app);
SERVER.installSubscriptionHandlers(httpServer);

const PORT = process.env.PORT || 5000;

httpServer.listen({ port: PORT }, () =>{
  console.log(`🚀 Server ready at http://localhost:${PORT}${SERVER.graphqlPath}`)
  console.log(`🚀 Subscriptions ready at ws://localhost:${PORT}${SERVER.subscriptionsPath}`)
})

Upvotes: 0

Views: 455

Answers (1)

Thomas Hennes
Thomas Hennes

Reputation: 9979

In the case of subscriptions, you're using web sockets instead of regular http requests, so your token is available elsewhere, namely under connection.context.Authorization (note the uppercase 'A'), connection being provided by the function attached to the context of your ApolloServer and being defined in the context of subscriptions.

You basically will want to move token verification to your ApolloServer declaration:

  const SERVER = new ApolloServer({
    typeDefs,
    resolvers,
    context: ({req, connection}) => ({
         Event,
         User,
         Message,
         currentUser: async () => {
           const token = connection
                         ? connection.context.Authorization
                         : req.headers.authorization
           return await jwt.verify(token, process.env.SECRET)
         },
      }),
    ...

This is a really bare bones example, you could check for the existence of req as well and generate an error if neither connection nor req are set, handle the case where there is no token, etc., but you get the basic idea.

See Context with Subscriptions in the Apollo Server docs for further reference.

Upvotes: 1

Related Questions