Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/ivangfr/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 React application called movies-ui.
https://github.com/ivangfr/springboot-react-keycloak
dicebear docker java javascript keycloak mapstruct mongodb oauth2-resource-server omdb-api pkce postgresql react semantic-ui-react spring-boot spring-data-mongodb spring-security springdoc-openapi web
Last synced: 7 days ago
JSON representation
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.
- Host: GitHub
- URL: https://github.com/ivangfr/springboot-react-keycloak
- Owner: ivangfr
- Created: 2019-06-30T06:23:37.000Z (over 5 years ago)
- Default Branch: master
- Last Pushed: 2024-08-17T15:20:54.000Z (3 months ago)
- Last Synced: 2024-08-18T14:15:50.313Z (3 months ago)
- Topics: dicebear, docker, java, javascript, keycloak, mapstruct, mongodb, oauth2-resource-server, omdb-api, pkce, postgresql, react, semantic-ui-react, spring-boot, spring-data-mongodb, spring-security, springdoc-openapi, web
- Language: JavaScript
- Homepage:
- Size: 49.8 MB
- Stars: 394
- Watchers: 15
- Forks: 151
- Open Issues: 3
-
Metadata Files:
- Readme: README.md
- Funding: .github/FUNDING.yml
Awesome Lists containing this project
README
# springboot-react-keycloak
The goal of this project is to secure `movies-app` using [`Keycloak`](https://www.keycloak.org/)(with PKCE). `movies-app` consists of two applications: one is a [Spring Boot](https://docs.spring.io/spring-boot/index.html) Rest API called `movies-api` and another is a [React](https://react.dev/) application called `movies-ui`.
## Proof-of-Concepts & Articles
On [ivangfr.github.io](https://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.
## Additional Readings
- \[**Medium**\] [**Implementing a Full Stack Web App using Spring-Boot and React**](https://medium.com/@ivangfr/implementing-a-full-stack-web-app-using-spring-boot-and-react-7db598df4452)
- \[**Medium**\] [**Using Keycloak to secure a Full Stack Web App implemented with Spring-Boot and React**](https://medium.com/@ivangfr/using-keycloak-to-secure-a-full-stack-web-app-implemented-with-spring-boot-and-react-6b2d80fc5c12)
- \[**Medium**\] [**Implementing and Securing a Simple Spring Boot REST API with Keycloak**](https://medium.com/@ivangfr/how-to-secure-a-spring-boot-app-with-keycloak-5a931ee12c5a)
- \[**Medium**\] [**Implementing and Securing a Simple Spring Boot UI (Thymeleaf + RBAC) with Keycloak**](https://medium.com/@ivangfr/how-to-secure-a-simple-spring-boot-ui-thymeleaf-rbac-with-keycloak-ba9f30b9cb2b)
- \[**Medium**\] [**Implementing and Securing a Spring Boot GraphQL API with Keycloak**](https://medium.com/@ivangfr/implementing-and-securing-a-spring-boot-graphql-api-with-keycloak-c461c86e3972)
- \[**Medium**\] [**Setting Up OpenLDAP With Keycloak For User Federation**](https://medium.com/@ivangfr/setting-up-openldap-with-keycloak-for-user-federation-82c643b3a0e6)
- \[**Medium**\] [**Integrating GitHub as a Social Identity Provider in Keycloak**](https://medium.com/@ivangfr/integrating-github-as-a-social-identity-provider-in-keycloak-982f521a622f)
- \[**Medium**\] [**Integrating Google as a Social Identity Provider in Keycloak**](https://medium.com/@ivangfr/integrating-google-as-a-social-identity-provider-in-keycloak-c905577ec499)
- \[**Medium**\] [**Building a Single Spring Boot App with Keycloak or Okta as IdP: Introduction**](https://medium.com/@ivangfr/building-a-single-spring-boot-app-with-keycloak-or-okta-as-idp-introduction-2814a4829aed)## Project diagram
![project-diagram](documentation/project-diagram.jpeg)
## Applications
- ### movies-api
`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 by `Keycloak` is provided.
`movies-api` stores its data in a [`Mongo`](https://www.mongodb.com/) database.`movie-api` has the following endpoints:
| Endpoint | Secured | Roles |
|-------------------------------------------------------------------|---------|----------------------------------|
| `GET /api/userextras/me` | Yes | `MOVIES_ADMIN` and `MOVIES_USER` |
| `POST /api/userextras/me -d {avatar}` | Yes | `MOVIES_ADMIN` and `MOVIES_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` and `MOVIES_USER` |- ### movies-ui
`React` frontend application where `users` can see and comment movies and `admins` can manage movies. In order to access the application, `user` / `admin` must login using his/her username and password. Those credentials are handled by `Keycloak`. All the requests coming from `movies-ui` to secured endpoints in `movies-api` have a access token (JWT) that is generated when `user` / `admin` logs in.
`movies-ui` uses [`Semantic UI React`](https://react.semantic-ui.com/) as CSS-styled framework.## Prerequisites
- [`Java 21+`](https://www.oracle.com/java/technologies/downloads/#java21)
- [`npm`](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm)
- [`Docker`](https://www.docker.com/)
- [`jq`](https://jqlang.github.io/jq/)
- [`OMDb API`](https://www.omdbapi.com/) 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` in `springboot-react-keycloak/movies-ui` folder with the following content:
```
REACT_APP_OMDB_API_KEY=
```## PKCE
As `Keycloak` supports [`PKCE`](https://datatracker.ietf.org/doc/html/rfc7636) (`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-keycloak` root folder run:
```
./init-environment.sh
```## Initialize Keycloak
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 the `movies-app` client;
- create the client role `MOVIES_ADMIN` for the `movies-app` client;
- create `USERS` group;
- create `ADMINS` group;
- add `USERS` group as realm default group;
- assign `MOVIES_USER` client role to `USERS` group;
- assign `MOVIES_USER` and `MOVIES_ADMIN` client roles to `ADMINS` group;
- create `user` user;
- assign `USERS` group to user;
- create `admin` user;
- assign `ADMINS` group to admin.## Running movies-app using Maven & Npm
- **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` and `Instagram`. I've written two articles in **Medium** where I explain step-by-step how to integrate [GitHub](https://medium.com/@ivangfr/integrating-github-as-a-social-identity-provider-in-keycloak-982f521a622f) and [Google](https://medium.com/@ivangfr/integrating-google-as-a-social-identity-provider-in-keycloak-c905577ec499).
- **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
```## Applications URLs
| Application | URL | Credentials |
|-------------|---------------------------------------|---------------------------------------|
| movie-api | http://localhost:9080/swagger-ui.html | [Access Token](#getting-access-token) |
| movie-ui | http://localhost:3000 | `admin/admin` or `user/user` |
| Keycloak | http://localhost:8080 | `admin/admin` |## Demo
- The gif below shows an `admin` logging in and adding one movie using the wizard feature:
![demo-admin](documentation/demo-admin.gif)
- The gif below shows a `user` logging in using his Github account; then he changes his avatar and comment a movie:
![demo-user-github](documentation/demo-user-github.gif)
## Testing movies-api endpoints
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`.
### 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
```
> **Note**: In [jwt.io](https://jwt.io), we can decode and verify the `JWT` 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](#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": []
}
]
```### Calling movies-api endpoints using Swagger
- 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](#getting-access-token)) in the `Value` field. Then, click `Authorize` and `Close` to finalize.
- Done! We can now access the secured endpoints.
## Useful Commands
- **MongoDB**
List all movies:
```
docker exec -it mongodb mongosh moviesdb
db.movies.find()
```
> Type `exit` to get out of MongoDB shell## Shutdown
- To stop `movies-api` and `movies-ui`, go to the terminals where they are running and press `Ctrl+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
```## How to upgrade movies-ui dependencies to latest version
- 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
```