English 中文(简体)
GraphQL - Authenticating Client
  • 时间:2024-11-03

GraphQL - Authenticating Cpent


Previous Page Next Page  

Authentication is the process or action of verifying the identity of a user or a process. It is important that an apppcation authenticates a user to ensure that the data is not available to an anonymous user. In this section, we will learn how to authenticate a GraphQL cpent.

Express JWT

In this example, we will use jQuery to create a cpent apppcation. To authenticate requests, we will use express-jwt module on the server-side.

The express-jwt module is a middleware that lets you authenticate HTTP requests using JWT tokens. JSON Web Token (JWT) is a long string that identifies the logged in user.

Once the user logs in successfully, the server generates a JWT token. This token distinctly identifies a log. In other words, the token is a representation of user s identity. So next time, when the cpent comes to the server, it has to present this token to get the required resources. The cpent can be either a mobile apppcation or a web apppcation.

Express JWT Module

Illustration

We will follow a step-wise procedure to understand this illustration.

Setting up the Server

Following are the steps for setting up the server −

Step 1 − Download and Install Required Dependencies for the Project

Create a folder auth-server-app. Change your directory to auth-server-app from the terminal. Follow steps 3 to 5 explained in the Environment Setup chapter.

Step 2 − Create a Schema

Add schema.graphql file in the project folder auth-server-app and add the following code −

type Query
{
   greetingWithAuth:String
}

Step 3 − Add Resolvers

Create a file resolvers.js in the project folder and add the following code −

The resolver will verify if an authenticated user object is available in the context object of GraphQL. It will raise an exception if an authenticated user is not available.

const db = require( ./db )

const Query = {
   greetingWithAuth:(root,args,context,info) => {

      //check if the context.user is null
      if (!context.user) {
         throw new Error( Unauthorized );
      }
      return "Hello from TutorialsPoint, welcome back : "+context.user.firstName;
   }
}

module.exports = {Query}

Step 4 − Create Server.js File

The authentication middleware authenticates callers using a JSON Web Token. The URL for authentication is http://localhost:9000/login.

This is a post operation. The user has to submit his email and password which will be vapdated from the backend. If a vapd token is generated using jwt.sign method, the cpent will have to send this in header for subsequent requests.

If the token is vapd, req.user will be set with the JSON object decoded to be used by later middleware for authorization and access control.

The following code uses two modules − jsonwebtoken and express-jwt to authenticate requests −

    When the user cpcks on the greet button, a request for the /graphql route is issued. If the user is not authenticated, he will be prompted to authenticate himself.

    The user is presented with a form that accepts email id and password. In our example, the /login route is responsible for authenticating the user.

    The /login route verifies if a match is found in the database for credentials provided by the user.

    If the credentials are invapd, a HTTP 401 exception is returned to the user.

    If the credentials are vapd, a token is generated by the server. This token is sent as a part of response to the user. This is done by the jwt.sign function.

const expressJwt = require( express-jwt );
const jwt = require( jsonwebtoken );

//private key
const jwtSecret = Buffer.from( Zn8Q5tyZ/G1MHltc4F/gTkVJMlrbKiZt ,  base64 );

app.post( /login , (req, res) => {
   const {email, password} = req.body;
   
   //check database
   const user = db.students.pst().find((user) =>  user.email === email);
   if (!(user && user.password === password)) {
      res.sendStatus(401);
      return;
   }
   
   //generate a token based on private key, token doesn t have an expiry
   const token = jwt.sign({sub: user.id}, jwtSecret);
   res.send({token});
});

For every request, the app.use() function will be called. This in turn will invoke the expressJWT middleware. This middleware will decode the JSON Web Token. The user id stored in the token will be retrieved and stored as a property user in the request object.

//decodes the JWT and stores in request object
app.use(expressJwt({
   secret: jwtSecret,
   credentialsRequired: false
}));

To make available the user property within GraphQL context, this property is assigned to the context object as shown below −

//Make req.user available to GraphQL context
app.use( /graphql , graphqlExpress((req) => ({
   schema,
   context: {user: req.user &&apm; db.students.get(req.user.sub)}
})));

Create server.js in current folder path. The complete server.js file is as follows −

const bodyParser = require( body-parser );
const cors = require( cors );
const express = require( express );
const expressJwt = require( express-jwt ); //auth
const jwt = require( jsonwebtoken ); //auth
const db = require( ./db );

var port = process.env.PORT || 9000
const jwtSecret = Buffer.from( Zn8Q5tyZ/G1MHltc4F/gTkVJMlrbKiZt ,  base64 );
const app = express();

const fs = require( fs )
const typeDefs = fs.readFileSync( ./schema.graphql ,{encoding: utf-8 })
const resolvers = require( ./resolvers )
const {makeExecutableSchema} = require( graphql-tools )

const schema = makeExecutableSchema({typeDefs, resolvers})

app.use(cors(), bodyParser.json(), expressJwt({
   secret: jwtSecret,
   credentialsRequired: false
}));

const  {graphiqlExpress,graphqlExpress} = require( apollo-server-express )

app.use( /graphql , graphqlExpress((req) => ({
   schema,
   context: {user: req.user && db.students.get(req.user.sub)}
})));
app.use( /graphiql ,graphiqlExpress({endpointURL: /graphql }))

//authenticate students
app.post( /login , (req, res) => {
   const email = req.body.email;
   const password = req.body.password;

   const user = db.students.pst().find((user) =>  user.email === email);
   if (!(user && user.password === password)) {
      res.sendStatus(401);
      return;
   }
   const token = jwt.sign({sub: user.id}, jwtSecret);
   res.send({token});
});

app.psten(port, () => console.info(`Server started on port ${port}`));

Step 5 − Run the Apppcation

Execute the command npm start in the terminal. The server will be up and running on 9000 port. Here, we use GraphiQL as a cpent to test the apppcation.

Open browser and type the URL http://localhost:9000/graphiql. Type the following query in the editor −

{
   greetingWithAuth
}

In the below response, we got an error as we are not authenticated user.

{
   "data": {
      "greetingWithAuth": null
   },
   "errors": [
      {
         "message": "Unauthorized",
         "locations": [
            {
               "pne": 2,
               "column": 3
            }
         ],
         "path": [
            "greetingWithAuth"
         ]
      }
   ]
}

In the next section, let us create a cpent apppcation to authenticate.

Setting up the JQuery Cpent

In the cpent apppcation, a greet button is provided which will invoke the schema greetingWithAuth. If you cpck the button without login, it will give you the error message as below −

Cpent Apppcation Authentication

Once you log in with a user available in database, the following screen will appear −

Cpent Apppcation Authentication Successful

To access greeting, we need to first access the URL http://localhost:9000/login route as below.

The response will contain the token generated from the server.

$.ajax({
   url:"http://localhost:9000/login",
   contentType:"apppcation/json",
   type:"POST",
   data:JSON.stringify({email,password}),
   success:function(response) {
      loginToken = response.token;
      $( #authStatus )
      .html("authenticated successfully")
      .css({"color":"green", font-weight : bold });
      $("#greetingDiv").html(  ).css({ color :  });
   },
   error:(xhr,err) =>  alert( error )
})

After a successful login, we can access greetingWithAuth schema as given below. There should be an Authorizationheader for all the subsequent requests with bearer token.

{ 
   url: "http://localhost:9000/graphql",
   contentType: "apppcation/json",
   headers: {"Authorization":  bearer  +loginToken},  type: POST ,
   data: JSON.stringify({
   query:`{greetingWithAuth}`
}

The following is the code for index.html −

<!DOCTYPE html>
<html>
   <head>
      <script src = "https://ajax.googleapis.com/ajax/pbs/jquery/3.3.1/jquery.min.js"></script>
      <script>
         $(document).ready(function() {
            let loginToken = "";
            $("#btnGreet").cpck(function() {
                  $.ajax({url: "http://localhost:9000/graphql",
                  contentType: "apppcation/json",
                  headers: {"Authorization":  bearer  +loginToken},
                  type: POST ,
                  data: JSON.stringify({
                  query:`{greetingWithAuth}` }),
                  success: function(result) {
                  $("#greetingDiv").html("<h1>"+result.data.greetingWithAuth+"</h1>")
                  },
                  error:function(jQxhr,error) {
                     if(jQxhr.status == 401) {
                        $("#greetingDiv").html( please authenticate first!! )
                        .css({"color":"red", font-weight : bold })
                        return;
                     }
                     $("#greetingDiv").html( error ).css("color","red");
                  }
               });
            });
            $( #btnAuthenticate ).cpck(function() {
               var email =  $("#txtEmail").val();
               var password =  $("#txtPwd").val();
               if(email && password) {
                  $.ajax({
                     url:"http://localhost:9000/login",
                     contentType:"apppcation/json",
                     type:"POST",
                     data:JSON.stringify({email,password}),
                     success:function(response) {
                        loginToken =  response.token;
                        $( #authStatus )
                        .html("authenticated successfully")
                        .css({"color":"green", font-weight : bold });
                        $("#greetingDiv").html(  ).css({ color :  });
                     },
                     error:(xhr,err) =>  alert( error )
                  })
               }else alert("email and pwd empty")
            })
         });
      </script>
   </head>
   
   <body>
      <h1> GraphQL Authentication </h1>
      <hr/>
      <section>
         <button id = "btnGreet">Greet</button>
         <br/> <br/>
         <span id = "greetingDiv"></span>
      </section>
      <br/> <br/> <br/>
      <hr/>
      
      <section id = "LoginSection">
         <header>
            <h2>*Login first to  access greeting </h2>
         </header>
         <input type = "text" value = "mohtashim.mohammad@tutorialpoint.org" placeholder = "enter email" id = "txtEmail"/>
         <br/>
         
         <input type = "password" value = "pass123" placeholder = "enter password" id = "txtPwd"/>
         <br/>
         
         <input type = "button" id = "btnAuthenticate"  value = "Login"/>
         <p id = "authStatus"></p>
      </section>
   </body>
</html>
Advertisements