Authentication

In this section, you’ll learn how you can implement authentication functionality with Apollo and Graphcool to provide a login to the user.

Prepare the Angular components

As in the sections before, you’ll set the stage for the login functionality by preparing the Angular components that are needed for this feature. You’ll start by implementing the Login component.

Let’s quickly gain an understanding of the structure of this new component which can have two important states.

  • One state is for users that already have an account and only need to login. In this state, the component will just render two input fields for the user to provide their email and password. Notice that login will be true in this case.
  • The second state is for users that haven’t created an account yet, and thus still need to sign up. Here, you also render a third input field where users can provide their name. In this case, login will be false.

The method confirm will be used to implement the mutations that we need to send for the login functionality.

Next, you also need to provide the src/app/constants.ts file that we use to define keys for the credentials that we’re storing in the browser’s localStorage.

With that component in place, you can go ahead and add a new route to your src/app/app.routing.module file.

Finally, go ahead and add the Login link to the Header component that allows users to navigate to the Login page.

You first subscribe to the isAuthenticated stream from authService and update the logged property. If the logged is false, the submit-button won’t be rendered anymore. That way you make sure only authenticated users can create new links.

You’re also adding a second button on the right side of the HeaderComponent that users can use to login and logout.

Here is what the LoginComponent and HeaderComponent components now look like:

Before you can implement the authentication functionality in src/app/login/login.component.ts, you need to prepare the Graphcool project and enable authentication on the server-side.

Enabling Email-and-Password Authentication & Updating the Schema

Authentication in the Graphcool Framework is based on resolver functions that deal with login-functionality by issuing and returning node tokens which are used to authenticate requests.

Graphcool has a lightweight and flexible template system that allows to conventiently pull in predefined functionality into a service. You’ll be using the email-password template for authentication.

You can use the CLI’s add-template command to use a template in your Graphcool service. This command will perform two major tasks:

  • Download the files from Graphcool’s templates repository that are required for the email-password template.
  • Add commented lines to graphcool.yml and types.graphql that allow you to “activate” the template’s functionality by uncommenting them and then invoking graphcool-framework deploy again.

This now downloaded six new files and placed them in the src/email-password directory. It also added comments to graphcool.yml and types.graphql.

Next, you have to actually “activate” the templates functionality by uncommenting these lines.

If you take a look at the code for these functions, you’ll notice that they’re referencing a User type that still needs to be added to your data model. In fact, the add-template command already wrote this User type to types.graphql - except that it still has comments.

Before you apply the changes to the running service, you’ll make another modification to your data model by adding the relation between the Link and the newly added User type as well as a new field name for the User.

You added two things to the schema:

  • A new field on the User type to store the name of the user.
  • A new relation between the User and the Link type that represents a one-to-many relationship and expresses that one User can be associated with multiple links. The relation manifests itself in the two fields postedBy and links.

Now it’s time to apply the changes by deploying your service again.

Your GraphQL API now includes three additional operations, as specified in graphcool.yml:

  • signup: Create a new user based on email and password.
  • authenticate: Log in existing user with email and password.
  • loggedInUser: Checks whether a user is currently logged in.

Adding an additional Argument to the signup Mutation

You can see the GraphQL interface for the newly added operations in the corresponding .graphql-files inside the server/src/email-password directory. Let’s take a look at the interface of the signup function:

type SignupUserPayload {
  id: ID!
  token: String!
}

extend type Mutation {
  signupUser(email: String!, password: String!): SignupUserPayload
}

The signupUser-mutation is used to create a new User in the database. The problem right now is that our schema requires every User instance to have a name. However, the above signupUser-mutation only accepts email and password as arguments. You now need to adjust the signup resolver so it also accepts the name for the new User as an input argument and make sure it’s saved when the User is created.

For now you only adjusted the interface of the signup resolver. Next, you also need to make sure to update the implementation.

Note: The signup resolver is implemented as a serverless function which will be deployed for you by the Graphcool Framework. The input arguments for that function are determined by the input arguments of the corresponding GraphQL operation. In this case, this is the signupUser-mutation, so the function will received three string as input arguments: email, password and name. (Notice that these are wrapped in a single object called event though.)

The goal in the new implementation is to retrieve the name argument from the input event and send it along when creating the new User.

All you do is also retrieve the name from the input event and then pass it to the createGraphcoolUser function a bit later.

All that’s left for you now is deploying these changes to make sure your running Graphcool service gets updated and exposes the new functionality in its API.

Perfect, you’re all set now to actually implement the authentication functionality in the frontend as well.

Implementing the Login Mutations

createUser and signinUser are two regular GraphQL mutations that you can use in the same way as you did with the createLink mutation from before.

Now, let’s gain a better understanding what’s going on in the two mutations that you just added to the src/app/graphql.ts file.

The SIGNIN_USER_MUTATION looks very similar to the mutations we saw before. It simply takes the email and password as arguments and returns info about the user as well as a token that you can attach to subsequent requests to authenticate the user. You’ll learn a bit how to do so.

The CREATE_USER_MUTATION however is a bit different! Here, we define two mutations at once! When you’re doing that, the execution order is always from top to bottom. So, in your case, the createUser mutation will be executed before the signinUser mutation. Bundling two mutations like this allow you to sign up and login in a single request!

All right, all that’s left to do is to call the two mutations inside the Login component!

The code is pretty straightforward. If the user wants to only login, you’re calling the SIGNIN_USER_MUTATION and pass the provided email and password as arguments. Otherwise, you’re using the CREATE_USER_MUTATION where you also pass the user’s name. After the mutation is performed, you are calling the authService that will take care of storing the data and navigating back to the root route.

You now need to make a couple more changes to src/app/app.component.ts to get things working.

  1. You inject the authService
  2. You try to log in automatically
  3. You set this userId on the $root $data object

You can now create an account by providing a name, email and password. Once you do so, the submit-button will be rendered again:

Updating the createLink-mutation

Since you’re now able to authenticate users and also added a new relation between the Link and User type, you can also make sure that every new link that gets created in the app can store information about the user that posted it. That’s what the postedBy field on Link will be used for.

There are two major changes. You first added another argument to the mutation that represents the id of the user that is posting the link. Secondly, you also include the postedBy information in the payload of the mutation.

Now you need to make sure that the id of the posting user is included when you’re calling the mutation in CreateLinkComponent.

For this to work, you also need to import the GC_USER_ID key.

Perfect! Before sending the mutation, you’re now also retrieving the corresponding user id from localStorage. If that succeeds, you’ll pass it to the call to CREATE_LINK_MUTATION so that every new Link will from now on store information about the User who created it.

If you haven’t done so before, go ahead and test the login functionality. Open http://localhost:4200/login. Then click the need to create an account?-button and provide some user data for the user you’re creating. Finally, click the create Account-button. If all went well, the app navigates back to the root route and your user was created. You can verify that the new user is there by checking the data browser or sending the allUsers query in a Playground.

Configuring Apollo with the Auth Token

Now that users are able to login and obtain a token that authenticates them against the Graphcool backend, you actually need to make sure that the token gets attached to all requests that are sent to the API.

Since all the API requests are actually created and sent by the HttpLink in your app, you need to make sure it knows about the user’s token. Luckily, Apollo provides a nice way for authenticating all requests by using headers. // TODO : update link to the docs

That’s it - now all your API requests will be authenticated if a token is available.

Note: In a real application you would now configure the authorization rules (permissions) of your project to define what kind of operations authenticated and non-authenticated users should be allowed to perform.

Unlock the next chapter
What are the names of the two mutations that are added to the Graphcool project after the Email+Password Auth Provider was enabled?
loginUser & logoutUser
signinUser & createUser
createUser & loginUser
signinUser & logoutUser