Securing GraphQL with Auth0

Unlike Rest API, which has multiple endpoints, it is a bit more tricky to secure GraphQL, as it is one endpoint where all the queries and mutations are made. Locking down the single endpoint on GraphQL, might not be the best option, but with Auth0, it gives us the flexibility to authenticate the user on the client and pass down the token down to the GraphQL server for authorization.

Go to Auth0, sign in, and create an APIs under Application

Screenshot 2021-07-22 at 4.56.13 PM.png

Click on Create API

Screenshot 2021-07-22 at 4.59.54 PM.png

Enter the name of your server, Identifier, and leave the Signing Algorithm, as it is

Screenshot 2021-07-22 at 5.03.35 PM.png

Lets get down to coding:

Install these libraries:

alternatively, you can use this library from @pointblankdev lambda-auth

In your server folder, create a new file named verify.js

const jwksClient = require("jwks-rsa");
const jwt = require("jsonwebtoken");

we created a function that can be used as a middleware that takes in the token and returns a promise, which returns a resolved if successful

const jwt = require("jsonwebtoken");
const jwksClient = require("jwks-rsa");

const verify = async (Token) => {
  const client = jwksClient({
    jwksUri: `https://${AUTH0_DOMAIN}/.well-known/jwks.json`,
  });

  function getJwksClientKey(header, callback) {
    client.getSigningKey(header.kid, function (error, key) {
      const signingKey = key.publicKey || key.rsaPublicKey;
      callback(null, signingKey);
    });
  }

  return new Promise((resolve, reject) => {
    jwt.verify(
      bearerToken,
      getJwksClientKey,
      {
        audience: process.env.AUDIENCE,
        issuer: `https://${AUTH0_DOMAIN}/`,
        algorithms: ["RS256"],
      },
      function (err, decoded) {
        if (err) reject(err);
        resolve(decoded);
      }
    );
  });
};
module.exports = { verify };

In the index.js, const { verifyToken } = require("./lib/verify");

use as middeware

 const server = new ApolloServerLocal({
    schema,
    context: async ({ req }) => {
      let isAuthenticated = false;
      try {
        const authHeader = req.headers.authorization || "";
        if (authHeader) {
          const token = authHeader.split(" ")[1];
          console.log(token);
          const payload = await verify(token);
          console.log("payload", payload);
          isAuthenticated = payload ? true : false;
        }
      } catch (error) {
        console.error(error);
      }
      return { isAuthenticated };
    },
  });

If it is authenticated, isAuthenticated = true

here, we can pass this down into our resolvers to protect the queries or mutation

const listBadges = async (src, args, { isAuthenticated }) => {  
  console.log("authentication", isAuthenticated);
  if (!isAuthenticated) {
    throw new Error("User not logged In");
  }
  return dynamite.Σ();
};

this is how we authorize on the server-side of GraphQL using auth0