springboot-react-keycloak
springboot-react-keycloak copied to clipboard
The goal of this project is to secure movies-app using Keycloak (with PKCE). movies-app consists of two applications: one is a Spring Boot Rest API called movies-api and another is a React application...
springboot-react-keycloak
The goal of this project is to secure movies-app using Keycloak(with PKCE). movies-app consists of two applications: one is a Spring Boot Rest API called movies-api and another is a ReactJS application called movies-ui.
Project diagram

Applications
-
movies-api
Spring BootWeb Java backend application that exposes a REST API to manage movies. Its secured endpoints can just be accessed if an access token (JWT) issued byKeycloakis provided.movies-apistores its data in aMongodatabase.movie-apihas the following endpointsEndpoint Secured Roles GET /api/userextras/meYes MOVIES_MANAGERandUSERPOST /api/userextras/me -d {avatar}Yes MOVIES_MANAGERandUSERGET /api/moviesNo GET /api/movies/{imdbId}No POST /api/movies -d {"imdb","title","director","year","poster"}Yes MOVIES_MANAGERDELETE /api/movies/{imdbId}Yes MANAGE_MOVIESPOST /api/movies/{imdbId}/comments -d {"text"}Yes MOVIES_MANAGERandUSER -
movies-ui
ReactJSfrontend application whereuserscan see and comment movies andadminscan manage movies. In order to access the application,user/adminmust login using his/her username and password. Those credentials are handled byKeycloak. All the requests coming frommovies-uito secured endpoints inmovies-apihave a access token (JWT) that is generated whenuser/adminlogs in.movies-uiusesSemantic UI Reactas CSS-styled framework.
Prerequisites
-
OMDb APIKEYTo use the
Wizardoption to search and add a movie, you need to get an API KEY from OMDb API. In order to do it, access https://www.omdbapi.com/apikey.aspx and follow the steps provided by the website.Once you have the API KEY, create a file called
.env.localinspringboot-react-keycloak/movies-uifolder with the following contentREACT_APP_OMDB_API_KEY=<your-api-key>
PKCE
As Keycloak supports PKCE (Proof Key for Code Exchange) since version 7.0.0, we are using it in this project.
Start Environment
-
In a terminal and inside
springboot-react-keycloakroot folder rundocker-compose up -d -
Wait for all Docker containers to be up and running. To check it, run
docker-compose ps
Running movies-app using Maven & Npm
-
movies-api
-
Open a terminal and navigate to
springboot-react-keycloak/movies-apifolder -
Run the following
Mavencommand to start the application./mvnw clean spring-boot:run -Dspring-boot.run.jvmArguments="-Dserver.port=9080"Once the startup finishes,
KeycloakInitializerRunner.javaclass will run and initializecompany-servicesrealm inKeycloak. Basically, it will create:- Realm:
company-services - Client:
movies-app - Client Roles:
MOVIES_MANAGERandUSER - Two users
admin: with rolesMANAGE_MOVIESandUSERuser: only with roleUSER
- Realm:
-
Social Identity Providers like
Google,Facebook,Twitter,GitHub, etc can be configured by following the steps described inKeycloakDocumentation
-
-
movies-ui
-
Open another terminal and navigate to
springboot-react-keycloak/movies-uifolder -
Run the command below if you are running the application for the first time
npm install -
Run the
npmcommand below to start the applicationnpm start
-
Applications URLs
| Application | URL | Credentials |
|---|---|---|
| movie-api | http://localhost:9080/swagger-ui/index.html | Access Token |
| movie-ui | http://localhost:3000 | admin/admin or user/user |
| Keycloak | http://localhost:8080/admin | admin/admin |
Demo
-
The gif below shows an
adminlogging in and adding one movie using the wizard feature
-
The gif below shows a
userlogging in using his Github account; then he changes his avatar and comment a movie
Testing movies-api endpoints
You can manage movies by accessing directly movies-api endpoints using the Swagger website or curl. However, for the secured endpoints like POST /api/movies, PUT /api/movies/{id}, DELETE /api/movies/{id}, etc, you need to inform an access token issued by Keycloak.
Getting Access Token
-
Open a terminal
-
Run the following commands to get the access token
ACCESS_TOKEN="$(curl -s -X POST \ "http://localhost:8080/realms/company-services/protocol/openid-connect/token" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "username=admin" \ -d "password=admin" \ -d "grant_type=password" \ -d "client_id=movies-app" | jq -r .access_token)" echo $ACCESS_TOKEN
Calling movies-api endpoints using curl
-
Trying to add a movie without access token
curl -i -X POST "http://localhost:9080/api/movies" \ -H "Content-Type: application/json" \ -d '{ "imdbId": "tt5580036", "title": "I, Tonya", "director": "Craig Gillespie", "year": 2017, "poster": "https://m.media-amazon.com/images/M/MV5BMjI5MDY1NjYzMl5BMl5BanBnXkFtZTgwNjIzNDAxNDM@._V1_SX300.jpg"}'It should return
HTTP/1.1 401 -
Trying again to add a movie, now with access token (obtained at #getting-access-token)
curl -i -X POST "http://localhost:9080/api/movies" \ -H "Authorization: Bearer $ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "imdbId": "tt5580036", "title": "I, Tonya", "director": "Craig Gillespie", "year": 2017, "poster": "https://m.media-amazon.com/images/M/MV5BMjI5MDY1NjYzMl5BMl5BanBnXkFtZTgwNjIzNDAxNDM@._V1_SX300.jpg"}'It should return
HTTP/1.1 201 { "imdbId": "tt5580036", "title": "I, Tonya", "director": "Craig Gillespie", "year": "2017", "poster": "https://m.media-amazon.com/images/M/MV5BMjI5MDY1NjYzMl5BMl5BanBnXkFtZTgwNjIzNDAxNDM@._V1_SX300.jpg" } -
Getting the list of movies. This endpoint does not requires access token
curl -i http://localhost:9080/api/moviesIt should return
HTTP/1.1 200 [ { "imdbId": "tt5580036", "title": "I, Tonya", "director": "Craig Gillespie", "year": "2017", "poster": "https://m.media-amazon.com/images/M/MV5BMjI5MDY1NjYzMl5BMl5BanBnXkFtZTgwNjIzNDAxNDM@._V1_SX300.jpg", "comments": [] } ]
Calling movies-api endpoints using Swagger
-
Access
movies-apiSwagger website, http://localhost:9080/swagger-ui/index.html -
Click
Authorizebutton. -
In the form that opens, paste the
access token(obtained at getting-access-token) in theValuefield. Then, clickAuthorizeandCloseto finalize. -
Done! You can now access the secured endpoints
Useful Commands
-
MongoDB
List all movies
docker exec -it mongodb mongo moviesdb db.movies.find()Type
exitto get out of MongoDB shell
Shutdown
-
To stop
movies-apiandmovies-ui, go to the terminals where they are running and pressCtrl+C -
To stop and remove docker-compose containers, network and volumes, go to a terminal and, inside
springboot-react-keycloakroot folder, run the command belowdocker-compose down -v
How to upgrade movies-ui dependencies to latest version
-
In a terminal, make sure you are in
springboot-react-keycloak/movies-uifolder -
Run the following commands
npm upgrade npm i -g npm-check-updates ncu -u npm install