⚠️ This lesson is retired and might contain outdated information.

Encrypt Passwords with a Serverless Function

Share this video with your friends

Social Share Links

Send Tweet
Published 4 years ago
Updated 2 years ago

Intercept requests from a GraphQL mutation using a Serverless Function. Use this function to encrypt user's passwords before persisting them to the database.

Instructor: [0:00] Here, we have a table that stores user's password as plain text. This is a very frowned upon practice. What we'd like to do is to extend our mutation in a way that whenever we try to create a user, we can hash this password before actually saving it to the database.

[0:25] Since we have this surveillance function already set up, most of what we'll be doing is moving the code you have here to that function. To start with, let's move the dependencies. I just copy the fetch dependency and paste it right here. We'll also need to import the bcrypt dependency.

[0:45] Of course, these dependencies are not yet installed, so we'll still install them shortly, bcrypt. Then we can go ahead and empty this function, because we don't need the boilerplate code anymore.

[1:00] The next thing we need to move is the actual query, which we intercepted earlier. This query is all we need to execute after this function has done its validation, or whatever task it needs to do.

[1:15] Then, we also need to copy the actual function that would execute this query. This execute function is responsible for executing this query. As you can see, it's calling the endpoint. We have the GraphQL engine endpoint, we have. The body is the query which we have right here, and the variables which we're going to pass this to the actual function when we're executing the function.

[1:42] We need to get the values for these variables from the request body. To do that, we can just copy this line of code that already extracts this information, and we can create a variable to hold the hashed password. This is going to be set by a function called hashPassword, which is going to take in a password, and use the bcrypt library to generate a hashed password.

[2:14] I already have this function imported right at the end of the file. We can see what's happening is that, it's calling the bcrypt.hash method, which is a callback API, and then it's converting that callback API into a Promise API. This way, we can wrap it in an async function, and then use our to get the hashed value from it.

[2:39] Now, in order to hash the password, we need to execute the query using that hashed password. We can copy the execute command here, and paste it right below the hashed password variable, and then change the password from password to hashed password. At this point, we can start sending out responses.

[3:06] If anything goes wrong, we want to send back an error with the status 400 code. This status code should be 400. Then you can set the message to errors.message. If that's not the case, if everything worked out fine, then we can send a response. We don't need to specify the status code if it's successful. The body is going to be everything that is returned from the data.

[4:00] Then, we need to make sure that we save the header, so that the content type is application/json. Content type should be application/json.

[4:18] Now, if you head back to the terminal, you can see that we are getting an error because the insert_user serverless function couldn't find the node-fetch library. We need to install both node-fetch and the Bcrypt library.

[4:35] To do that, we run npm install --save bcrypt, and node-fetch. Give this a few seconds. It should pull down the code from NPM, down to your serverless function. Now I can go ahead and start this function once more, func start. Hopefully, everything works out fine.

[5:08] Now if you head back to the browser and take a look at the GraphQL, instead of executing this insert_user mutation, which is what the engine generates for you, we want to execute the insert_user, which is action we created.

[5:25] Let's delete everything we have here, delete everything we have in the query variables, and go back to mutations and add insertUser, not insert_user. Add a username, that name is Jane and a password, this can be Jane's password. We can return all the affected rules as well.

[5:56] Now, if we run this, well, we got an error. Let's take a look at what we did wrong. If we take a look at, it terminally says that "The variable password have already been declared."

[6:09] Let's take a look at our code. Yeah, I think this is where we messed up, so I need to take out this particular line and save. Then we can see if it get to work this time. If we try to insert once more, yeah, we have unaffected rule.

[6:25] If we go to the data and go to the user table, you can see that Jane's password is now hashed. If someone is looking at the database, they won't just be able to tell what the actual password of Jane is.

Kofi Ocran
Kofi Ocran
~ 4 years ago

This is the error I'm getting.

{
  "errors": [
    {
      "extensions": {
        "internal": {
          "type": "http_exception",
          "message": "ConnectionFailure Network.Socket.getAddrInfo (called with preferred socket type/protocol: AddrInfo {addrFlags = [AI_ADDRCONFIG], addrFamily = AF_UNSPEC, addrSocketType = Stream, addrProtocol = 0, addrAddress = <assumed to be undefined>, addrCanonName = <assumed to be undefined>}, host name: Just \"host.docker.internal\", service name: Just \"7071\"): does not exist (Name or service not known)"
        },
        "path": "$",
        "code": "unexpected"
      },
      "message": "http exception when calling webhook"
    }
  ]
}

The url in my handler is http://host.docker.internal:7071/api/insertUser so I can't figure out the error.

Markdown supported.
Become a member to join the discussionEnroll Today