React Login Authentication

Most of the below is based on the tutorials avalible at digitalocean.com

Token storage

When adding Authentication (asking the user to type in login details) the details (normally a token) need to be store somewhere.

The common options are:

  • localStorage (for all tabs, only cleared by you, could be a security concearn)
  • sessionStorage (just for that tab, lost when the tab is closed but remains when the tab is refreshed)
  • redux or context
  • cookies (considered deprecated)

Implementation

  1. Build an API that returns a JWT

  2. Create a custom hook, this will provide setToken

  3. Create a login component at /src/components/Login/Login.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import './Login.css';
import { loginUser } from '../../services/loginUser';
import { useGlobalUserActionsContext } from '../../context/GlobalContextProvider';

export default function Login({ setToken }) {
const [username, setUserName] = useState();
const [password, setPassword] = useState();
const setUsername = useGlobalUserActionsContext();

const handleSubmit = async (e) => {
e.preventDefault();
const response = await loginUser({
username,
password,
});
setUsername('Welcome ' + response.displayName + '!');
setToken(response);
};

return (
<div className="login-wrapper">
<h1>Please Log In</h1>
<form onSubmit={handleSubmit}>
<label>
<p>Username</p>
<input type="text" onChange={(e) => setUserName(e.target.value)} />
</label>
<label>
<p>Password</p>
<input
type="password"
onChange={(e) => setPassword(e.target.value)}
/>
</label>
<div>
<button type="submit">Submit</button>
</div>
</form>
</div>
);
}

Login.propTypes = {
setToken: PropTypes.func.isRequired,
};
  1. At the App level display the component for all routes but conditionally hide it based on the existance of the token
1
2
3
4
5
6
7
8
9
10
const App = () => {
const { token, setToken } = useToken();

if (!token) {
return <Login setToken={setToken} />;
}

return (
<div>
<Router>
  1. So now once the user authenticates the usage of useState in the custom hook will cause a re-render.

Boom, the user is logged in.

Note that getToken would need to be exported if you want to include the token in subsequent API calls to the BFF.

References