This is an example application showing how to use JWT authentication within a React app using Spring as a backend.
This application uses MariaDB as a database. To run it you can use
Docker. Run the docker-compose.yml
file in the root folder which will setup
everything automatically:
- download mariadb image
- setup root password of mysql admin user (root)
- create database (p3admin_db)
- bind container to port 3306
When you run the BackendApplication
then a CommandLineRunner
is executed that creates some default
roles and users:
- Roles
- Admin
- Therapist
- Secretary
- Users
- admin/admin
- therapist/therapist
- secretary/secretary
The configuration
package contains the essentials for the JWT security setup. In the SecurityCfg
class you will
find HttpSecurity
configuration which blocks any REST calls to /api/v1/roles
if a user does
not have the ADMIN role.
.antMatchers("/api/v1/refresh-token").permitAll()
.antMatchers("/api/v1/roles").hasRole(Role.RoleType.ADMIN.name())
The filter
package contains the JWT specifics for any request made to the backend.
The JwtAuthenticationFilter
is responsible for the authentication via username and password. If it receives valid
credentials then an AUTH and REFRESH token is created and returned in the HttpResponse.
The JwtAuthorizationFilter
is then used for each future request to validate the passed JWT Token and to inform Spring
about the authorities (=roles) that this request has.
If the AUTH token is expired then a user can refresh it by using the /refresh-token
endpoint of the UserController
.
Here are some example http requests:
### login with admin
curl -X POST --location "http://localhost:8080/api/v1/login" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "username=admin&password=admin"
### refresh a token
curl -X POST --location "http://localhost:8080/api/v1/refresh-token" \
-H "Authorization: Bearer %JWT_REFRESH_TOKEN%"
### getUsers
curl -X GET --location "http://localhost:8080/api/v1/users?page=0&pageSize=50" \
-H "Authorization: Bearer %JWT_AUTH_TOKEN%"
### getRoles - this will not work for the user secretary because of missing admin role
curl -X GET --location "http://localhost:8080/api/v1/roles?page=0&pageSize=50" \
-H "Authorization: Bearer %JWT_AUTH_TOKEN%"
The frontend is a very basic React application in Typescript using Material UI and Axios.
It has a Login page where you can change the theme between light and dark. Also, in case of an error it will show that. Forgot Password? is not implemented.
After a successful login it fetches the users of the backend with axios. Axios is configured to use interceptors to
automatically refresh the JWT Token whenever necessary and to provide the auth token for each request. Also, the user with its tokens and roles
is stored in the localStorage
until the user logs out or the token cannot be refreshed anymore. The code can be found
in the api.ts
and auth-service.ts
.