Applying Authentication

In the last section, you implemented a signup and login mutation which both return authentication token for your users. In this section, you’ll learn how you can use authentication tokens to associate an incoming request with a user of your application.

Creating a relation between User and Link

Looking back at the requirements from the “Getting Started”-section, we actually stated that only authenticated users should be able to create new Link elements. However, right now, the post mutation is available for everyone - so you should change that to properly account for that requirement!

The first thing to do is update the data model again! You want to create a relationship between the User and the Link type which expresses that one User can post many Links.

To apply these changes, you need to deploy the Prisma database service again.

All right! With these changes, you express that a Link node can be associated with a User node via the postedBy and links fields. However, you also need to make sure that this data is properly entered into the database when a post mutation is received, so you need to adjust the post resolver!

Adjusting the post resolver

If you’re taking a look at the Prisma schema (in src/generated/prisma.graphql), in particular the createLink mutation, you’ll notice that the LinkCreateInput (the type that wraps all input arguments for this mutation) now has an additional field:

input LinkCreateInput {
  description: String!
  url: String!
  postedBy: UserCreateOneWithoutLinksInput
}

Without going in too much detail about the generated types here, this basically means that when creating a new Link node using the createLink mutation, you can now directly provide the id (or even the email because that’s also a @unique field) of a specific User to express that the new Link was postedBy that User.

Consider for example the following mutation:

mutation {
  createLink(data: {
    url: "https://www.graphql.org",
    description: "Official GraphQL Website",
    postedBy: {
      connect: {
        email: "johndoe@graph.cool"
      }
    }
  }) {
    id
  }
}

This mutation not only creates a new Link node, but it also sets the postedBy field of that new Link to the User who is identified by the email johndoe@graph.cool. As mentioned above, you can use both the id and the email field to uniquely identify a User.

Note that this mutation will fail if no User with the provided email exists - in that case, no Link element will be created either!

Now it’s time to actually make the required changes to your code.

The difference to the previous version is that this time you’re first retrieving the user’s id from the context (you’ll implement getUserId in just a bit) and then pass it to the createLink-mutation as a value for the connect argument - just like in the sample mutation from above.

To make this work, you still need a function called getUserId that’s able to retrieve the id of a User from the context that’s passed down the resolver chain.

The context argument has a request property representing the incoming HTTP request which carries the query or mutation. Consequently, the request property provides access to the headers of the incoming HTTP request. As authentication tokens are expected to be carried in the Authorization header field, you can retrieve the value of that field with context.request.get('Authorization').

Additionally, the actual authentication token is prepended with the following string "Bearer ", so in order to access the raw token you need to get rid of that prefix. Once the token was retrieved, it can be verified using the jsonwebtoken library. Note that jwt.verify returns a JSON object with the encoded payload (or throws an error in case the token is not valid). Since the payload contains the id of the User the token was issued for, you now finally have access to a valid id of an authenticated User.

Finally, to make this work there are two small things left to. First, you need to import jwt as it’s used inside the getUserId function, then of course make sure the function gets exported.

Fantastic! Let’s go and test if the post mutation now actually works when creating a new Link on behalf of an authenticated User.

Authenticating a User

We already discussed how you can obtain an authentication token for a given User of your application but we haven’ yet talked about how you can use them in order to make authenticated requests on behalf of a specific User.

Here is how it works:

  1. In the Playground, send the signup or login mutation to obtain an authentication token from your GraphQL server
  2. Set the token as the Authorization header in the Playground
  3. Send a post mutation to create a new Link element

Let’s go through these steps together!

To verify that everything worked and the new Link was indeed postedBy the User who the token belongs to, you can send the feed query like so:

{
  feed {
    description
    postedBy {
      email
    }
  }
}

If everything worked correctly, the feed query now returns this item as part of the list:

{
  "description": "Weekly GraphQL Newsletter",
  "postedBy": {
    "email": "johndoe@graph.cool"
  }
}

Adding a vote mutation

The last feature you’ll implement in this section is a vote mutation, allowing authenticated Users to cast a vote for a specific Link.

Recall the steps for creating adding a new feature to your GraphQL API:

  1. Adjust data model (if necessary)
  2. Deploy Prisma database service to apply changes to data model (if necessary)
  3. Add new root field (on the Query, Mutation or Subscription field) to application schema
  4. Implement the resolver for the new root field

In this case, you need to start with adjusting the data model, since right now it doesn’t allow for a voting feature.

To make sure the Prisma database service is aware of these changes, you need to deploy them.

The new type is now added and CRUD operations for Vote have been added to the Prisma schema (you can check src/generated/prisma.graphql to convince yourself of that).

The next step is to add the root field for the voting mutation.

Since you’re now referencing the Vote type in the application schema without defining or importing it, the server won’t work. So go ahead and import the Vote type into from the Prisma schema into your application schema.

Finally, you need to implement the vote resolver.

In the vote resolver, you’re first retrieving the userId from the HTTP header again (using the familiar getUserId function you just implemented) so you can create the Vote on behalf of an actual User. What follows is a check to ensure the Link to be voted for actually exists. Lastly, the resolver invokes the createVote mutation from the Prisma API to create a new Vote in the database connecting the given User and Link nodes.

That’s it! You can now restart the server and send the vote mutation in your app Playground.

Unlock the next chapter
What is the "connect" argument in a Prisma mutation used for?
It connects your application schema with the Prisma schema
It creates a TCP connection
It's used to connect two nodes in the database via a relation
There is connect argument in Prisma mutations