Auth0 authentication in a React website

In a couple of posts I’ll go through setup of Auth0 authentication for your website (React.js) and API server followed with examples in GitHub repositories. Primary reason for writing/documenting this is to cut down time next time I need to set it all up again.

Objective

Current post will cover the following:

  • Set up of new Auth0.com application
  • Bootstrap of basic React website
  • Custom hook and integration with Auth0 SDK by following example steps
  • Further enhancements

About

Authentication is a sensitive subject and there are many permutations and possibilities of its implementation. Figuring out the constraints of the system is a first step in the right direction.

For almost any commercial website out there in the wild a login and/or signup is a must. Whether it is a user profile that needs to be filled, or maybe user is contributing content to the system, or it is a subscription based API access - people are expected to land on some screen or get a popup asking for some sort of credentials to be able to continue. First thing first - you need to know your audience and preferably how often they will access the system and how many new users will possibly come to your site every once in a while, with this knowledge it is easier to choose a better approach.

Current example - Auth0 - might be suitable for businesses that do not expect infinite amounts of user signups otherwise it could become quite expensive. On the other hand if you have hundreds of thousands of users then money should not be a problem.

Alternatives

Some other user authentication solutions/products to consider:

Basic setup

You should know that Auth0 provides some useful examples both on their website as posts and on GitHub, I’ll follow their steps before applying my changes:

Setup on Auth0.com

In essence you need a couple of things, first create an application and then update some minor details in settings to be able to login when running locally. Application addons and connections (those are additional settings) are left with default values.

Create Auth0 application

Picture below shows their dialog for creating an application.

auth0 create application dialog
Create application in Auth0.com

Update application settings

  • Name - Auth0 React example
  • Application Type - Single Page Application
  • Allowed Callback URLs - http://localhost:3000
  • Allowed Web Origins - http://localhost:3000
  • Allowed Logout URLs - http://localhost:3000
  • Allowed Origins (CORS) - http://localhost:3000

All the rest are left to their default values. I do also use localhost:3000 as this is what react app will use locally.

Basic React website

Provided there are so many examples of react app structure I will stick to using create-react-app scripts - it will give some basic recognizable structure to the app. To keep things simple I will also use react router with just a couple of routes.

$ npx create-react-app test-auth0-react-login

Above will produce the following directory structure (git commit) in a newly created directory test-auth0-react-login:

.
├── node_modules/
│   └── **
├── public/
│   ├── favicon.ico
│   ├── index.html
│   ├── logo192.png
│   ├── logo512.png
│   ├── manifest.json
│   └── robots.txt
├── src/
│   ├── App.css
│   ├── App.js
│   ├── App.test.js
│   ├── index.css
│   ├── index.js
│   ├── logo.svg
│   ├── serviceWorker.js
│   └── setupTests.js
├── README.md
├── package-lock.json
└── package.json

Add login/signup

Auth0 documented steps in auth0.com/docs/quickstart/spa/react:

So far it is a basic login experience as visible in the gif image below.

auth0 create application dialog
Login is working

Profile page

I’m still following Auth0 steps here:

Further enhancements

Before website is deployed it seems to be optional but helpful to improve existing implementation. It comes from experience of running similar authentication implementation in production.

Update Auth0 hook

Remove popup login option I am not keen on using popup login due to couple of issues:

  • popup would not always open in the same display when you have multiple of those,
  • it does not work on all browsers the same way (remember EasyXDM?)

Get and decode access token to have more details about the authentication like roles and scopes. This is not the same as primary ID token.

const getTokenSilently = async () => {
    const accessToken = await auth0Client.getTokenSilently();
    return { raw: accessToken, decoded: jwt_decode(accessToken) };
};

Set defaults in useState() instead of Auth0 example ones where they use undefined.

const [isAuthenticated, setIsAuthenticated] = useState(false);
const [user, setUser] = useState(null);
const [auth0Client, setAuth0] = useState(null);
const [loading, setLoading] = useState(true);

Import config directly instead of relying on props do import configuration file in the hook itself. Also ask for scopes we want to see all possible scopes user might have after they log in.

import config from './auth_config';

//...

const auth0FromHook = await createAuth0Client({
    domain: config.domain,
    client_id: config.clientId,
    scope: config.scope,
    redirect_uri: config.loginCallbackUrl
});

Scope check helper Ability to check if user has an expected scope.

const hasAnyScopeAsync = async (scopes) => {
    const token = await getTokenSilently();
    const tokenScopes = (token.decoded.scope || '').split(/\W/);
    return scopes && scopes.length && scopes.some(s => tokenScopes.indexOf(s) > -1);
};

Add logout redirect url Redirect user to homepage after logging out.

const logoutWithRedirect = () => auth0Client.logout({
  returnTo: config.logoutRedirectUrl
});

Additional changes

  • Hint on expected Node.js version through .nvmrc file and set version to 12.
  • Add "homepage" property to package.json to generate correct links when deploying to GitHub pages.
  • Use “homepage” (from package.json) as production redirect uri.
  • Add production URLs to Auth0 config, in my case:
    • Allowed Callback URLs - http://localhost:3000, https://ivarprudnikov.github.io/react-auth0-template
    • Allowed Web Origins - http://localhost:3000, https://ivarprudnikov.github.io
    • Allowed Logout URLs - http://localhost:3000, https://ivarprudnikov.github.io/react-auth0-template
    • Allowed Origins (CORS) - http://localhost:3000, https://ivarprudnikov.github.io
  • Add build version number (timestamp) to make sure index.html always changes upon every build.
  • Add Bootstrap styling

Source code and demo

For the purposes of a demo source code is deployed and hosted on GitHub pages.

Older post

React and Micronaut authentication templates

January 2, 2020
Templates to authenticate users and then authorize them to access an API on Lambda. By using a free Auth0 account. Another idea doomed to fail.
Continue reading
Newer post

Talk - Securing web applications with minimal resources

February 16, 2020
Had a chance to speak in “Cork|Sec” meetup here in Ireland, the event was busy enough. People filled the area on the first floor in a pub called “An Spailpin Fanach”.
Continue reading