Search code examples
reactjsapollojwt

Apollo. How to allow login/registration queries without jwt token check?


How to allow login/registration queries without jwt token check ?

I have a problem with getting jwt token for Login / Registration queries in Apollo. I try to understand how to don't check check correctness jwt token for queries (Mutations) Login / Registration. For example for first login in my app i don't have token and accordingly an empty string or null or undefined doesn't correct and I can't call query Login / Registration.

I try to check token in context.

const getTokenPayload = async (token?: string) => {
  try {
    return await jwt.verify(token, config.jwtSalt);
  } catch (e) {
    throw new ApolloError(`Token doesn't valid`, errorCodes.ERROR_TOKEN_IS_NOT_VALID);
  }
};

const apolloServerStart = (store) => {
  const server = new ApolloServer({
    context: async ({ req }) => {
      const tokenPayload = await getTokenPayload(req.headers.authorization);

      return {
        userId: tokenPayload.id,
      };
    },
    typeDefs,
    resolvers,
    dataSources: () => ({
      userAPI: new UserAPI({ store }),
      cardSetAPI: new CardSetAPI({ store }),
    }),
  });

  const app = express();
  server.applyMiddleware({ app });

  app.listen(
    { port: 4000 },
    () => console.log(`Server ready at http://localhost:4000${server.graphqlPath}`) // eslint-disable-line no-console
  );
};

connectToDb(apolloServerStart);

Solution

  • When instantiating the ApolloServer, in the context generation function you mustn't throw any errors if JWT is missing.

    context: async ({ req }) => {
      let userId = null;
      try {
        const tokenPayload = await jwt.verify(req.headers.authorization, config.jwtSalt);
        userId = tokenPayload?.id;
      } catch (err) {}
    
      return {
        userId
      };
    }
    

    The code above, will let EVERY request pass down to resolvers, no matter if JWT is invalid/missing or not. So then you have to protect your PRIVATE resolvers (make sure only logged users' requests reach them).To do that, you can define a so called "Guard". This is a function which wraps a resolver, checks if userId exists in the context, and returns an error to the client in case token is invalid (userId is null).

    Just wrap ALL your private resolvers with the guard func. Don't wrap the Login & Register resolvers with the GUARD func. This way, non-authenticated users can call them!