Search code examples
expressauthenticationgraphqlapollo-server

How to Prevent Code Execution in Apollo Server Resolvers When User is Unauthenticated?


I am facing an issue with Express Apollo Server. I am attempting to create an API that includes some resolvers, and not all of them require authentication. When the user is authenticated, everything works correctly. However, if the user is not authenticated, I encounter an error.

The problem lies in the fact that the response is already sent from the middleware. However, the function also needs to return, resulting in the following error:

Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client

Here is the relevant code snippet:

const loginRequiredGql = (req, res, next) => {
  const nextWrapper = () => {};
  for (const middleware of auth.loginRequired) {
    middleware(req, res, nextWrapper);
  }
  // if the response is already sent then the useris not authenticated
  console.log(res.headersSent);
}

const resolvers = {
  Query: {
    hello: (root, args, { req, res }) => {
      return 'World';
    },

    auth_test: (root, args, { req, res }) => {
      loginRequiredGql(req, res);
      if (!res.headersSent) return "some code";

      // The problem is that this code will be executed even if the user is not logged in.
      // I want to stop the execution of the code if the user is not logged in.
      // I tried to use return, but it didn't work.
      console.log("============  ");
      // return ;
    },
  }
};

How can I prevent the execution of the code if the user is not logged in? The use of return doesn't seem to work in this context. Any suggestions or guidance would be greatly appreciated.


Solution

  • I think that I've found a solution. My main idea is to directly send a response from the middlewares. In my updated approach, I check if the user is authenticated, and if not, I throw an error to forcefully stop the resolver. The error is then used to send a response

    
    const loginReqGql = (req,res,next) => {
      const nextWrapper = () => {};
      auth.isAuthenticated(req,res,nextWrapper);
      if (!req.user) {
        const error = new Error('Not authenticated!');
        error.statusCode  = 401;
        throw error;
      }
    }
    
    
    const resolvers = {
      Query: {
        hello: (root, args, { req,res }) => {
          return 'World'},
    
        auth_test:  (root, args, { req,res }) => {
          loginReqGql(req,res);
          // my code
          return 'authenticated';
        
        },
      }
    
    };
    

    I'm now wondering if this approach makes sense and if there are any ways to improve it. Any insights or suggestions would be helpful!