Apollo login mutation

We are now going to edit our GraphQL schema and implement the matching resolver function. Let's start with the schema and a new mutation to the RootMutation object of our schema.js file:

login (
email: String!
password: String!
): Auth

The preceding schema gives us a login mutation that accepts an email address and a password. Both are required to identify and authenticate the user. We then need to respond with something to the client. For now, the Auth type returns a token, which is a JWT in our case. You might want to add a different option according to your requirements:

type Auth {
token: String
}

The schema is now ready. Head over to the resolvers file and add the login function inside the mutation object. Before doing this, we have to install and import two new packages:

npm install --save jsonwebtoken bcrypt

The jsonwebtoken package handles everything required to sign, verify, and decode JWTs.

The important part is that all passwords for our users are not saved as plain text but are first encrypted using hashing, including a random salt. This generated hash cannot be decoded or decrypted to a plain password, but the package can verify if the password that was sent with the login attempt matches with the password hash saved on the user. Import these packages at the top of the resolvers file:

import bcrypt from 'bcrypt';
import JWT from 'jsonwebtoken';

The login function receives email and password as parameters. It should look like the following code:

login(root, { email, password }, context) {
return User.findAll({
where: {
email
},
raw: true
}).then(async (users) => {
if(users.length = 1) {
const user = users[0];
const passwordValid = await bcrypt.compare(password,
user.password);
if (!passwordValid) {
throw new Error('Password does not match');
}
const token = JWT.sign({ email, id: user.id }, JWT_SECRET, {
expiresIn: '1d'
});

return {
token
};
} else {
throw new Error("User not found");
}
});
},

The preceding code goes through the following steps:

  1. We query all users where the email address matches.
  2. If a user is found, we can go on. It is not possible to have multiple users with the same address, as the MySQL unique constraint forbids this.
  3. Next, we use the user password and compare it with the submitted password, using the bcrypt package, as explained previously.
  1. If the password was correct, we generate a JWT token to the jwt variable using the jwt.sign function. It takes three arguments: the payload, which is the user id and their email address; the key with which we sign the JWT; and the amount of time in which the JWT is going to expire.
  2. In the end, we return an object containing our JWT.
Something that you might need to rethink is how much detail you give in an error message. For example, we might not want to distinguish between an incorrect password and a non-existent user. It gives possible attackers or data collectors the opportunity to know which email address is in use.

The login function is not working yet, because we are missing JWT_SECRET, which is used to sign the JWT. In production, we use the environment variables to pass the JWT secret key into our back end code so that we use this approach in development too.

For Linux or Mac, you can use the following command directly in the Terminal:

export JWT_SECRET=awv4BcIzsRysXkhoSAb8t8lNENgXSqBruVlLwd45kGdYjeJHLap9LUJ1t9DTdw36DvLcWs3qEkPyCY6vOyNljlh2Er952h2gDzYwG82rs1qfTzdVIg89KTaQ4SWI1YGY

The export function sets the JWT_SECRET environment variable for you. Replace the JWT provided with a random one. You can use any password generator by setting the character count to 128 and excluding any special characters. Setting the environment variable allows us to read the secret in our application. You have to replace it when going to production.

Insert the following code at the top of the file:

const { JWT_SECRET } = process.env;

This code reads the environment variable from the global Node.js process object. Be sure to replace the JWT once you publish your application, and be sure to always store the secret securely. After letting the server reload, we can send the first login request. We are going to take a look how to do this in React later, but the following code shows an example using Postman:

{
"operationName":null,
"query": "mutation login($email : String!, $password : String!) {
login(email: $email, password : $password) { token }}",
"variables":{
"email": "[email protected]",
"password": "123456789"
}
}

This request should return a token:

{
"data": {
"login": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6InRlc3QxQGV4YW1wbGUuY29tIiwiaWQiOjEsImlhdCI6MTUzNzIwNjI0MywiZXhwIjoxNTM3MjkyNjQzfQ.HV4dPIBzvU1yn6REMv42N0DS0ZdgebFDX-Uj0MPHvlY"
}
}
}

As you can see, we have generated a signed JWT and returned it within the mutation's response. We can go on and send the token with every request inside the HTTP authorization header. We can then get the authentication running for all the other GraphQL queries or mutations that we have implemented so far. 

Let's continue and learn how to set up React to work with our authentication on the back end.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.216.34.146