The backend is a simple Express REST API application providing:
- a public end point returning a list of items:
GET
http://localhost:3000/api/public-items
- a private end point returning a list of items, which requires authentication:
GET
http://localhost:3000/api/private-items
- an end point, simulating authentication, and returning in the body object the Jason web Token in the property
token
:POST
http://localhost:3000/api/login
- The React application has been built with Vite, and uses React Router Dom version 6.
- UI customization is performed with TailwindCSS
- The login page is located at the route:
/auth/signin
- Authentication in this example is made with an
email
and apassword
. Since there is no real connection to a database implemented in this demo, we simulate a successful login with the following credentials:- email: anything starting with
good@
- password:
good
- email: anything starting with
- Any other combination will either produce a 422 error
- The submission of the form ultimately perform a
POST
request withaxios
tohttp://localhost:3000/api/login
passing theemail
andpassword
in the body.
import axios from 'axios';
import { Credentials } from '../models/credentials';
export async function authSignIn(credentials: Credentials): Promise<null> {
const {data} = await axios.post('http://localhost:3000/api/login', credentials);
if (data.token) {
localStorage.setItem('token', data.token);
}
return null;
}
- The server responds with an object containing:
- a
message
property containing some text - a
token
property containing the generated JWT token
- a
router.post('/', (req: Request, res: Response) => {
// data validation
const credentials: Credentials = req.body;
// ...
const token: string = jwt.sign(
{
email: credentials.email
},
process.env.JWT_TOKEN_SECRET,
{
algorithm: JWT_ALGORITHM,
expiresIn: '1d',
subject: credentials.email,
}
);
res.status(200).send({ message: 'Authenticated succesfully', token });
});
- When the token is present in the response body, we save the token in the
localStorage
for later use when we need authentication
- The page
/private
issues aGET
request to the protected APIhttp://localhost:3000/api/private-items
- This API expected to have a valid JWT token present in the header
Authorization
. - To achieve that we pass to
axios
an options paramaters setting the headers according to the token present or not in localStorage:
import axios from 'axios';
import { Item } from '../../models/item';
export async function getPrivateItems(): Promise<Item[]> {
const token: string | null = localStorage.getItem('token');
const {data} = await axios.get<Item[]>('http://localhost:3000/api/private-items', {
headers: {
'Authorization': token ? `Bearer ${token}` : undefined,
},
});
return data;
};
```