We want to build an application that displays a list of movies with the appropriate poster, title, and user ratings. Everyone should be able to see the ratings of these movies, but only the reviewers can add movies and ratings. We'll assume there is a poll of user votes where the reviewers just get the ratings in form of percentages and add to the platform.

We'll make use of GraphQL to build the data schema for the application. In fact, we don't need to worry about spinning up our own backend with a custom database and configuring the APIs. We'll make use of Graphcool. Graphcool gives developers a production-ready GraphQL backend to build better apps faster.

Brief Introduction to GraphQL

GraphQL is a query language for APIs created by Facebook that offers declarative data fetching in the client and is already used by companies such as Coursera and GitHub.

A GraphQL server exposes a schema that describes its API including queries to fetch data and mutations, to modify data.

This allows clients to specify their data requirements with queries and send it to one GraphQL endpoint instead of collecting information from multiple endpoints, as is typical with REST. While queries are a very easy and quick way for clients to get exactly the data they need in one request, the GraphQL server has to parse and validate the query, check which fields are included, and return the underlying data from the database.

The type-safe schema unlocks new possibilities for tooling, as demonstrated by GraphQL, which is maintained by Facebook. Check out how GitHub employs GraphQL for its API.

Use Graphcool

Graphcool is a serverless GraphQL backend that enables mobile and web developers to build production ready apps faster. You don't have spin up your own GraphQL server or think of spinning up a separate database.

Go ahead and install graphcool:

npm install -g graphcool

Then, run the following command:

graphcool init

It will create a project.graphcool file that contains a default Schema. Go ahead and edit the schema to be like this:

Build The Frontend

After installing globally, go ahead and scaffold a new ReactJS app like so:

create-react-app rottentomatoes

Note: We have a custom React script that comes bundled with Auth0 authentication. So you can use create-react-app to boostrap an app with authentication support with create-react-app my-app --scripts-version auth0-react-scripts. Then open http://localhost:3000 o see your app.

Note: create-react-app automatically invokes Yarn for installation. If you don't have Yarn installed, it falls back to use npm.

Build the Nav Component

The Nav.js file is our Nav component. Go ahead and add code to it like so:

apollo-client is one of the most popular GraphQL clients available. It makes interacting with a GraphQL backend seamless. It comes bundled with features like caching, query batching, and realtime updates via subscriptions.

This code above injects the addMovie function to the props of our CreateMovie component and makes it possible for a create operation query to happen on the backend with the values of the movie description, imageUrland avgRating. Adding mutations to React components is similar to adding queries, but instead of injected data, functions are injected for each mutation. It's that simple!

Build the Listmovie Component

The ListMovie component will be responsible for displaying the list of movies on the landing page. Create a component/ListMovie.js file and the following code:

Replace uri with your Graphcool endpoint. A network interface is created and passed to the Apollo Client. Now, the ApolloProvider is wrapping our Router to ensure that all child components can access the functionality from Apollo Client to send queries and perform mutations.

Now, run your app. There should be nothing on the landing page because you haven't added any movies. Head over to the /create URL and add a new movie.

Add a few movies. Now your landing page should look like this:

Awesome! Right now, everyone can view and create movies. Next, let's make sure only authenticated users can add movies.

Add Authentication to Your App

Auth0 allows us to issue JSON Web Tokens (JWTs). If you don't already have an Auth0 account, for a free one now.

Login to your Auth0 management dashboard and let's create a new API client. Click on the APIs menu item and then the Create API button. You will need to give your API a name and an identifier. The name can be anything you choose, so make it as descriptive as you want. The identifier will be used to identify your API, this field cannot be changed once set. For our example, I'll name the API Rotten Tomatoes and for the identifier I'll set it as http://rottentomatoes.com. We'll leave the signing algorithm as RS256 and click on the Create API button.

Creating the Rotten Tomatoes API.

Create the Auth Service

We'll create an authentication service to handle everything about authentication in our app. Go ahead and create an AuthService.js file inside the utilsdirectory.

Before we add code, you need to install jwt-decode and auth0-js node packages like so:

In the code above, we are using an hosted version of Auth0 in the login method and passed in our credentials.

The Auth0 package calls the Auth0's authorize endpoint. With all the details we passed to the method, our client app will be validated and authorized to perform authentication. You can learn more about the specific values that can be passed to the authorize method here.

The parameters that you do not have yet are the {AUTH0_CLIENT_ID} and the {YOUR_CALLBACK_URL}. When you created your API, Auth0 also created a test client which you can use. Additionally, you can use any existing SPA Auth0 client found in Clients section of your management dashboard.

A client was created automatically when you created the API. Now, go to the clients area and check for the test client that was created. You should see it in your list of clients. Open the client and change the Client Type to Single Page Application.

Non-interactive clients are meant to be used in machine-to-machine interactions. We are using a SPA to interact with the API so the client should be a SPA client. Check out Implicit Grant and client credentials exchange for more information.

Copy the CLIENT ID and replace it with the value of AUTH0_CLIENT_ID in the variable CLIENT_ID. Replace your callback url with http://localhost:3000/callback. Don't forget to add that to the Allowed Callback URLs and http://localhost:3000 to the Allowed Origins (CORS).

We also checked whether the token has expired via the getTokenExpirationDate and isTokenExpired methods. The isLoggedInmethod returns true or false based on the presence and validity of a user id_token.

Finally, we implemented a middleware, the requireAuth method. We'll use this method to protect the /special route from being accessed for non-loggedIn users.

Let's go update the Nav component to hide/show the login and logout buttons based on the user's authentication status.

We imported login, logout , and isLoggedIn functions from the AuthService. Then, we attached the login() and logout() functions to the login and logout buttons respectively.

We also hid the /create link by checking the authentication status of the user via the isLoggedIn() function.

Add a Callback Component

We will create a new component and call it Callback.js. This component will be activated when the localhost:3000/callback route is called and it will process the redirect from Auth0 and ensure we received the right data back after a successful authentication. The component will store the access_token and id_token.

Once a user is authenticated, Auth0 will redirect back to our application and call the /callback route. Auth0 will also append the id_token as well as the access_token to this request, and our Callback component will make sure to properly process and store those tokens in localStorage. If all is well, meaning we received an id_token, and access_token, we will be redirected back to the / page and will be in a logged-in state.

Add Some Values to Auth0 Dashboard

Just before you try to log in or sign up, head over to your Auth0 dashboard and add http://localhost:3000/callback to the Allowed Callback URLs and http://localhost:3000 to Allowed Origins (CORS).

Secure the Special Route

We need to ensure that no one can go to the browser and just type /create to access the movie route.

Open up index.js and add an onEnter prop with a value of requireAuth to the /create route like so:

Now you are logged in. Perfect! A user can't create a new movie without been authenticated.

We have successfully handled authentication on the frontend, but something is missing. Our GraphQL endpoints are not secured. Anybody can get access to our endpoints and make fetch queries and mutations.

Secure GraphQL Endpoints

Head over to Graphcool. Thankfully, it ships with Permission systems and Auth0. Click on the User System as shown below. Also, click on the Configure Auth Provider highlighted below:

Click on Integrations and enable Auth0.

Copy your Auth0 Client Credentials and paste it here.

Now, click on Permissions. We need to restrict permission on the type of user that perform certain operations.

Right now, everyone can create movies. Let's change that to ensure only authenticated users can!

Click on the Everyone field and update it to make sure only authenticated users can create.

Now, if a user isn't authenticated, he or she can't create movies.

Head back to your app. Open up src/index.js file and remove the onEnterhook for the /create route.

Now, run your app and try to create a movie. Aha! Something went wrong, it doesn't work. Check your console.

GraphQL has now made it impossible for just any user to create a movie. You have to be authenticated to have the privilege! Whoop! Whoop!

Conclusion

In this tutorial, we covered how easy it is to build a product with a backend like Graphcool and add authentication to it easily using Auth0.