Access JWT Secured Jhipster API from a React App

Himanshu Pratap
3 min readAug 23, 2021

Scenario:

You have an Jhipster API server which is secured by JWT.

For example, here
Authentication URL — http://localhost:8080/api/authenticate
Endpoint URL — http://localhost:8080/api/students

In order to access these API through react application, we follow following steps.

  1. POST request to authentication API with request body in format below.
{"username":"admin","password":"admin","rememberMe":false}

2. The response body and response header after successful authentication has bearer token in following format.

Response Body

{
"id_token" : "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsImF1dGgiOiJST0xFX0FETUlOLFJPTEVfVVNFUiIsImV4cCI6MTYyOTg2Nzc4MX0.tdp_w6lMx_hdNalVBvSNBxXKf8sgkD-i7fa5wNyV8NZlkddjGyO26nmhHicqg16LCm6jR_TIVuVO2fPrA-2gKQ"
}

Response Header

{Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsImF1dGgiOiJST0xFX0FETUlOLFJPTEVfVVNFUiIsImV4cCI6MTYyOTg2Nzc4MX0.tdp_w6lMx_hdNalVBvSNBxXKf8sgkD-i7fa5wNyV8NZlkddjGyO26nmhHicqg16LCm6jR_TIVuVO2fPrA-2gKQ}

3. Extract the token either from response body or response header and save it to state variable, browsers’s SessionStorage, LocalStorage as per your requirement.

Note: LocalStorage and sessionStorage are relatively new APIs (meaning, not all legacy browsers will support them) and are near identical with the sole exception of persistence. SessionStorage is only available for the duration of the browser session (and is deleted when the tab or window is closed). LocalStorage survive page reloads. Note that the data stored in localStorage and sessionStorage can easily be read or changed from within the client/browser so should not be relied upon for storage of sensitive or security-related data within applications.

4. Make the API call to endpoint URL with request header having authorization bearer token (just like the one received in response header after successful authentication in Step3 )

{ Authorization: Bearer  eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsImF1dGgiOiJST0xFX0FETUlOLFJPTEVfVVNFUiIsImV4cCI6MTYyOTg2Nzc4MX0.tdp_w6lMx_hdNalVBvSNBxXKf8sgkD-i7fa5wNyV8NZlkddjGyO26nmhHicqg16LCm6jR_TIVuVO2fPrA-2gKQ}

The complete code is as folows:

Login.tsx

import React, {useState} from 'react';
import {TextField, Button} from 'reactstrap';
import axios from 'axios';
import HomePage from './HomePage';
const Login = () => { const [bearerId, setBearerId] = useState("");
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const [rememberMe, setRememberMe] = useState(false);
const [isAuthenticated, setIsAuthenticated] = useState(false);
const onSubmitLogin = (e: React.MouseEvent<HTMLButtonElement>): void => {
const loginUrl = 'http://localhost:8080/api/authenticate';
const AUTH_TOKEN_KEY = 'jhi-authenticationToken';
e.preventDefault();
// POST request to authentication url,
// extract bearer token from response and
// set state variable and set cookies localStorage
axios.post(loginUrl, { username, password, rememberMe })
.then(res => {
const bearerToken = res.headers.authorization;
if (bearerToken && bearerToken.slice(0, 7) === 'Bearer ') {
const jwt = bearerToken.slice(7, bearerToken.length);
localStorage.setItem(AUTH_TOKEN_KEY, jwt);
setBearerId(jwt);
setIsAuthenticated(true);
}
})
.catch(err => console.log(err.message));
}
const onLogout = () =>{
const AUTH_TOKEN_KEY = 'jhi-authenticationToken';
setIsAuthenticated(false);
setBearerId("");
localStorage.removeItem( AUTH_TOKEN_KEY);
}
return (
<>
// if not authenticated, display login form
{!isAuthenticated &&
<div>
<TextField
value={username}
onChange={event => setUsername(event.target.value)} />
<TextField
type="password"
value={password}
onChange={event => setPassword(event.target.value)} />
<Button
type="submit"
onClick={e => onSubmitLogin(e)} >Sign In</Button>
</div>
}
//If authenticated, display Homepage & logout button
{isAuthenticated &&
<div>
<HomePage />
<Button
type="submit"
onClick={onLogout} >Logout</Button>
</div>
}
</>
);
}
export default LogIn;

Above code references to two function onSubmitLogin() & onLogout() and one component HomePage.

HomePage.tsx

import React,{useState} from 'react';
import {Button} from 'reactstrap';
import axios from 'axios';
type IStudent= {
id: number;
name: string;
};
const HomePage = () => {const [student, setStudent] = useState<[IStudent]>(
[{id: 0,name: "" }] );
const getStudent =() =>{
const endpointUrl = 'http://localhost:8080/api/students';
const authHeader = "Bearer "+ localStorage.getItem('jhi-authenticationToken');
// authentication header added to request while making call to API

axios.get(endpointUrl, { headers: { 'Authorization': authHeader } } )
.then(res => setLocation(res.data))
.catch(err => console.log(err.message));
}
return (
<>
<br />
<Button
type="submit"
onClick={getStudent}
> Get Students</Button>
{ student.length > 1 &&
student.map(s => <p key= {s.id}>{s.name}</p> )
}
</>
);
}
export default HomePage;

Bibliography:

https://stackoverflow.com/questions/19867599/what-is-the-difference-between-localstorage-sessionstorage-session-and-cookies

--

--