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 called movies-ui
.
On ivangfr.github.io, I have compiled my Proof-of-Concepts (PoCs) and articles. You can easily search for the technology you are interested in by using the filter. Who knows, perhaps I have already implemented a PoC or written an article about what you are looking for.
- [Medium] Implementing a Full Stack Web App using Spring-Boot and React
- [Medium] Using Keycloak to secure a Full Stack Web App implemented with Spring-Boot and React
- [Medium] Implementing and Securing a Simple Spring Boot REST API with Keycloak
- [Medium] Implementing and Securing a Simple Spring Boot UI (Thymeleaf + RBAC) with Keycloak
- [Medium] Implementing and Securing a Spring Boot GraphQL API with Keycloak
- [Medium] Setting Up OpenLDAP With Keycloak For User Federation
- [Medium] Integrating GitHub as a Social Identity Provider in Keycloak
- [Medium] Integrating Google as a Social Identity Provider in Keycloak
- [Medium] Building a Single Spring Boot App with Keycloak or Okta as IdP: Introduction
-
Spring Boot
Web Java backend application that exposes a REST API to manage movies. Its secured endpoints can just be accessed if an access token (JWT) issued byKeycloak
is provided.movies-api
stores its data in aMongo
database.movie-api
has the following endpoints:Endpoint Secured Roles GET /api/userextras/me
Yes MOVIES_ADMIN
andMOVIES_USER
POST /api/userextras/me -d {avatar}
Yes MOVIES_ADMIN
andMOVIES_USER
GET /api/movies
No GET /api/movies/{imdbId}
No POST /api/movies -d {"imdb","title","director","year","poster"}
Yes MOVIES_ADMIN
DELETE /api/movies/{imdbId}
Yes MOVIES_ADMIN
POST /api/movies/{imdbId}/comments -d {"text"}
Yes MOVIES_ADMIN
andMOVIES_USER
-
React
frontend application whereusers
can see and comment movies andadmins
can manage movies. In order to access the application,user
/admin
must login using his/her username and password. Those credentials are handled byKeycloak
. All the requests coming frommovies-ui
to secured endpoints inmovies-api
have a access token (JWT) that is generated whenuser
/admin
logs in.movies-ui
usesSemantic UI React
as CSS-styled framework.
-
OMDb API
KEYTo use the
Wizard
option to search and add a movie, we 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 we have the API KEY, create a file called
.env.local
inspringboot-react-keycloak/movies-ui
folder with the following content:REACT_APP_OMDB_API_KEY=<your-api-key>
As Keycloak
supports PKCE
(Proof Key for Code Exchange
) since version 7.0.0
, we are using it in this project.
In a terminal and inside springboot-react-keycloak
root folder run:
./init-environment.sh
In a terminal and inside springboot-react-keycloak
root folder run:
./init-keycloak.sh
This script will:
- create
company-services
realm; - disable the required action
Verify Profile
; - create
movies-app
client; - create the client role
MOVIES_USER
for themovies-app
client; - create the client role
MOVIES_ADMIN
for themovies-app
client; - create
USERS
group; - create
ADMINS
group; - add
USERS
group as realm default group; - assign
MOVIES_USER
client role toUSERS
group; - assign
MOVIES_USER
andMOVIES_ADMIN
client roles toADMINS
group; - create
user
user; - assign
USERS
group to user; - create
admin
user; - assign
ADMINS
group to admin.
-
movies-api
-
Open a terminal and navigate to
springboot-react-keycloak/movies-api
folder; -
Run the following
Maven
command to start the application:./mvnw clean spring-boot:run -Dspring-boot.run.jvmArguments="-Dserver.port=9080"
-
We can also configure Social Identity Providers such as,
GitHub
,Google
,Facebook
andInstagram
. I've written two articles in Medium where I explain step-by-step how to integrate GitHub and Google.
-
-
movies-ui
-
Open another terminal and navigate to
springboot-react-keycloak/movies-ui
folder; -
Run the command below if you are running the application for the first time:
npm install
-
Run the
npm
command below to start the application:npm start
-
Application | URL | Credentials |
---|---|---|
movie-api | http://localhost:9080/swagger-ui.html | Access Token |
movie-ui | http://localhost:3000 | admin/admin or user/user |
Keycloak | http://localhost:8080 | admin/admin |
-
The gif below shows an
admin
logging in and adding one movie using the wizard feature: -
The gif below shows a
user
logging in using his Github account; then he changes his avatar and comment a movie:
We can manage movies by accessing directly movies-api
endpoints using the Swagger website or curl
. For the secured endpoints like POST /api/movies
, PUT /api/movies/{id}
, DELETE /api/movies/{id}
, etc, we need to inform an access token issued by Keycloak
.
-
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
Note: In jwt.io, we can decode and verify the
JWT
access token.
-
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", "comments": [] }
-
Getting the list of movies. This endpoint does not requires access token:
curl -i http://localhost:9080/api/movies
It 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": [] } ]
-
Access
movies-api
Swagger website, http://localhost:9080/swagger-ui.html. -
Click
Authorize
button. -
In the form that opens, paste the
access token
(obtained at getting-access-token) in theValue
field. Then, clickAuthorize
andClose
to finalize. -
Done! We can now access the secured endpoints.
-
MongoDB
List all movies:
docker exec -it mongodb mongosh moviesdb db.movies.find()
Type
exit
to get out of MongoDB shell
-
To stop
movies-api
andmovies-ui
, go to the terminals where they are running and pressCtrl+C
; -
To stop and remove docker containers, network and volumes, go to a terminal and, inside
springboot-react-keycloak
root folder, run the command below:./shutdown-environment.sh
-
In a terminal, make sure you are in
springboot-react-keycloak/movies-ui
folder; -
Run the following commands:
npm upgrade npm i -g npm-check-updates ncu -u npm install