Tutorial: building a static site with authentication using React and Netlify Identity
A tutorial showing how to add an authentication system to a static Netlify site with React, without touching the existing code
As an agency, we often use Middleman together with DatoCMS for our projects, because it's definitely one of the simplest and fastest ways to build a static website. Everything runs smoothly with Middleman until you have to deal with processes that need more complex dynamic interaction, and by far the most requested is the ability to authenticate users.
Since this is a common problem, we wanted to share with the rest of the world our experiment in adding Netlify Identity to our usual stack, which turned out to be a clean, easy-to-install solution. Using React made it even simpler, sparing us from getting tangled up in Ajax and jQuery or having to switch to JavaScript generators like Gatsby. React is a much simpler and more flexible tool for handling dynamic interaction, fairly easy to set up, and reusable across different projects. Plus, since we use Netlify to host our static websites, we wanted to give its Identity feature a try, which handles user management and authentication.
The experiment was a success, and we now use this solution extensively at Cantiere Creativo.
To sum up, here's the full stack we chose for this tutorial:
- Middleman as the generator, but you can use your favorite ;)
- React to build a user interface for the authentication part.
- Netlify to host our website and Netlify Identity through the GoTrue JS library to manage our registered users.
- DatoCMS to manage content.
- GoTrue API, an open-source API service for handling authentication.
The goal
To make the "before and after" effect clearer, we cloned a "The Office" fan site built with Middleman and DatoCMS, which you can find among the DatoCMS example sites. Download the original project here. The goal is to make the “Seasons” page accessible only to people who have an account, as if it were a premium content page.
For this tutorial we'll only show how to show/hide the link to that page, but the next step would be to make the gating more robust with a lambda function that returns the content via React only to authenticated users. This post doesn't aim to go deep into technicalities; it aims to share the reasoning behind our choice of this stack and pass on a bit of knowledge with a working example :)
The final result will look roughly like this
r>
Please enter your details
Netlify offers two options for working with Identity: a widget for a quick solution, and an open-source library, GoTrue JS, which essentially exposes the methods the widget uses. The big advantage of the library over the widget is that it lets you design your own interface, staying on brand and keeping the overall user experience consistent without adding weight to the page.
Netlify and its super-fast setup
We preferred to stay true to our web designer's work and chose the Netlify Identity client.
yarn add gotrue-js
To let Netlify manage your site's users, you need to enable “Identity” in your Netlify account.
For this tutorial we enabled the option that allows sign-up without a confirmation email, and we'll only demonstrate the signup/signin methods, but we encourage you to experiment with everything GoTrue JS offers.
React to the rescue
Whichever generator you've chosen, we'll let React build the interface and decide who can see our premium content.
So basically we give React the following jobs:
- Rendering a signin/logout button.
- Showing a sign-in/sign-up form that lets the user authenticate.
- Hiding/showing the premium content to the user.
In the javascript folder, create a folder named "auth" to keep the React files separate from the other scripts. Then add an index.js file that lets React “hook into” our static HTML.
import ReactDOM from "react-dom";
import React from "react";
import App from "./App";
ReactDOM.render(<App />, document.getElementById("react-root"));The tree should have a structure like this
|- source
...
|- javascripts
|- auth
|- App.js
|- AuthBar.js
|- AuthForm.js
|- index.jsBefore enabling React you should configure Webpack and Babel; here you'll find a tutorial for a minimal setup.
Routing
The App.js file will act as the router of our React app and return the appropriate component according to the authentication logic. To do this we use React Router.
AuthBar.js will show the authentication menu as part of the main navigation bar, using a React portal. So in our navbar.html we need to add a div with an id (“#header-auth-navbar”) to “hook” the React component into.
header.main-navigation ... = link_to "Homepage", "/index.html" #header-auth-navbar
Checking whether a user is logged in
First, we need a method that checks whether the user is logged in, so we can decide what content to show. To do this we create an HOC component that listens for the current user and updates the DOM accordingly.
We also need to show the link to the “Seasons” page only to authenticated users. To do this we just check the props.currentUser passed down by our HOC component. The sign-in link will point to the route we created in the router, while logout will call the GoTrue JS .logout() method, which deletes the current session, and then redirect to the home page.
The authentication form
The logic of a sign-up form and a sign-in form is similar, even though they need different API calls, so for now we'll only cover the sign-in action, while in the example project we split the signin/signup actions by URL. We'll use Formik to build the form, because it provides some handy methods for managing component state. Using Formik's .onSubmit() function, when the form is submitted we call GoTrueJS's .login() method with three arguments: email, password and a third argument that saves the current session (not documented in the Netlify docs). The query checks whether a user with that email exists in the Netlify project and then saves a session with an expiration date or, if not, saves the error message in the component state. At that point you can print the error by checking whether this.state.error exists.
auth.login(values.email, values.password, true)
.then(response => {
actions.setSubmitting(false);
Alert.success('You signed in successfully!');
this.props.history.push("/");
})
.catch(error => {
this.setState({error: error.json.error_description});
actions.setSubmitting(false);
});As a result, once logged in, the user should see the link to the premium content, a welcome message and the logout link.
In conclusion, adding an authentication system to a static site opens up a lot of possibilities. With this simple bit of logic you can start building a complex website, even from this example, with things like an admin area, premium users, services, etc., while keeping all the advantages of a static website!