{"id":18048055,"url":"https://github.com/ivangfr/springboot-react-keycloak","last_synced_at":"2025-04-08T08:11:42.846Z","repository":{"id":37575059,"uuid":"194482782","full_name":"ivangfr/springboot-react-keycloak","owner":"ivangfr","description":"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.","archived":false,"fork":false,"pushed_at":"2025-03-05T17:00:05.000Z","size":51647,"stargazers_count":434,"open_issues_count":3,"forks_count":168,"subscribers_count":15,"default_branch":"master","last_synced_at":"2025-04-01T05:34:06.400Z","etag":null,"topics":["dicebear","docker","java","javascript","keycloak","mongodb","oauth2-resource-server","omdb-api","pkce","postgresql","react","semantic-ui-react","spring-boot","spring-data-mongodb","spring-security","spring-web-mvc","springdoc-openapi"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ivangfr.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"ivangfr"}},"created_at":"2019-06-30T06:23:37.000Z","updated_at":"2025-03-31T07:51:57.000Z","dependencies_parsed_at":"2024-12-07T15:01:53.716Z","dependency_job_id":"4ce6e3d8-3f07-4944-b2cf-087f6dd5901b","html_url":"https://github.com/ivangfr/springboot-react-keycloak","commit_stats":{"total_commits":138,"total_committers":1,"mean_commits":138.0,"dds":0.0,"last_synced_commit":"ee230136a64789a26b775a6aa58b054d0b734d09"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ivangfr%2Fspringboot-react-keycloak","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ivangfr%2Fspringboot-react-keycloak/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ivangfr%2Fspringboot-react-keycloak/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ivangfr%2Fspringboot-react-keycloak/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ivangfr","download_url":"https://codeload.github.com/ivangfr/springboot-react-keycloak/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247801170,"owners_count":20998339,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dicebear","docker","java","javascript","keycloak","mongodb","oauth2-resource-server","omdb-api","pkce","postgresql","react","semantic-ui-react","spring-boot","spring-data-mongodb","spring-security","spring-web-mvc","springdoc-openapi"],"created_at":"2024-10-30T20:11:06.673Z","updated_at":"2025-04-08T08:11:42.822Z","avatar_url":"https://github.com/ivangfr.png","language":"JavaScript","funding_links":["https://github.com/sponsors/ivangfr"],"categories":[],"sub_categories":[],"readme":"# springboot-react-keycloak\n\nThe 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`.\n\n## Proof-of-Concepts \u0026 Articles\n\nOn [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.\n\n## Additional Readings\n\n- \\[**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)\n- \\[**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)\n- \\[**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)\n- \\[**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)\n- \\[**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)\n- \\[**Medium**\\] [**Setting Up OpenLDAP With Keycloak For User Federation**](https://medium.com/@ivangfr/setting-up-openldap-with-keycloak-for-user-federation-82c643b3a0e6)\n- \\[**Medium**\\] [**Integrating GitHub as a Social Identity Provider in Keycloak**](https://medium.com/@ivangfr/integrating-github-as-a-social-identity-provider-in-keycloak-982f521a622f)\n- \\[**Medium**\\] [**Integrating Google as a Social Identity Provider in Keycloak**](https://medium.com/@ivangfr/integrating-google-as-a-social-identity-provider-in-keycloak-c905577ec499)\n- \\[**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)\n\n## Project diagram\n\n![project-diagram](documentation/project-diagram.jpeg)\n\n## Applications\n\n- ### movies-api\n\n  `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.\n  \n  `movies-api` stores its data in a [`Mongo`](https://www.mongodb.com/) database.\n\n  `movie-api` has the following endpoints:\n\n  | Endpoint                                                          | Secured | Roles                            |\n  |-------------------------------------------------------------------|---------|----------------------------------|\n  | `GET /api/userextras/me`                                          | Yes     | `MOVIES_ADMIN` and `MOVIES_USER` |\n  | `POST /api/userextras/me -d {avatar}`                             | Yes     | `MOVIES_ADMIN` and `MOVIES_USER` | \n  | `GET /api/movies`                                                 | No      |                                  |\n  | `GET /api/movies/{imdbId}`                                        | No      |                                  |\n  | `POST /api/movies -d {\"imdb\",\"title\",\"director\",\"year\",\"poster\"}` | Yes     | `MOVIES_ADMIN`                   |\n  | `DELETE /api/movies/{imdbId}`                                     | Yes     | `MOVIES_ADMIN`                   |\n  | `POST /api/movies/{imdbId}/comments -d {\"text\"}`                  | Yes     | `MOVIES_ADMIN` and `MOVIES_USER` |\n\n- ### movies-ui\n\n  `React` frontend application where `users` can see and comment movies and `admins` can manage movies. To access the application, `user` / `admin` must login using his/her username and password. Those credentials are managed by `Keycloak`. All the requests from `movies-ui` to secured endpoints in `movies-api` include an access token (JWT) that is generated when `user` / `admin` logs in.\n  \n  `movies-ui` uses [`Semantic UI React`](https://react.semantic-ui.com/) as CSS-styled framework.\n\n## Prerequisites\n\n- [`Java 21`](https://www.oracle.com/java/technologies/downloads/#java21) or higher;\n- [`npm`](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm)\n- A containerization tool (e.g., [`Docker`](https://www.docker.com), [`Podman`](https://podman.io), etc.)\n- [`jq`](https://jqlang.github.io/jq/)\n- [`OMDb API`](https://www.omdbapi.com/) KEY\n\n  To use the `Wizard` option to search and add a movie, we need to get an API KEY from OMDb API. To do this, access https://www.omdbapi.com/apikey.aspx and follow the steps provided by the website.\n\n  Once we have the API KEY, create a file called `.env.local` in the `springboot-react-keycloak/movies-ui` folder with the following content:\n  ```\n  REACT_APP_OMDB_API_KEY=\u003cyour-api-key\u003e\n  ```\n\n## PKCE\n\nAs `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. \n\n## Start Environment\n\nIn a terminal, navigate to the `springboot-react-keycloak` root folder and run:\n```\n./init-environment.sh\n```\n\n## Initialize Keycloak\n\nIn a terminal and inside the `springboot-react-keycloak` root folder run:\n```\n./init-keycloak.sh\n```\n\nThis script will:\n- create `company-services` realm;\n- disable the required action `Verify Profile`;\n- create `movies-app` client;\n- create the client role `MOVIES_USER` for the `movies-app` client;\n- create the client role `MOVIES_ADMIN` for the `movies-app` client;\n- create `USERS` group;\n- create `ADMINS` group;\n- add `USERS` group as realm default group;\n- assign `MOVIES_USER` client role to `USERS` group;\n- assign `MOVIES_USER` and `MOVIES_ADMIN` client roles to `ADMINS` group;\n- create `user` user;\n- assign `USERS` group to user;\n- create `admin` user;\n- assign `ADMINS` group to admin.\n\n## Running movies-app using Maven \u0026 Npm\n\n- **movies-api**\n\n  - Open a terminal and navigate to the `springboot-react-keycloak/movies-api` folder;\n\n  - Run the following `Maven` command to start the application:\n    ```\n    ./mvnw clean spring-boot:run -Dspring-boot.run.jvmArguments=\"-Dserver.port=9080\"\n    ```\n\n  - 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).\n\n- **movies-ui**\n\n  - Open another terminal and navigate to the `springboot-react-keycloak/movies-ui` folder;\n\n  - Run the command below if you are running the application for the first time:\n    ```\n    npm install\n    ```\n\n  - Run the `npm` command below to start the application:\n    ```\n    npm start\n    ```\n\n## Applications URLs\n\n| Application | URL                                   | Credentials                           |\n|-------------|---------------------------------------|---------------------------------------|\n| movie-api   | http://localhost:9080/swagger-ui.html | [Access Token](#getting-access-token) |\n| movie-ui    | http://localhost:3000                 | `admin/admin` or `user/user`          |\n| Keycloak    | http://localhost:8080                 | `admin/admin`                         |\n\n## Demo\n\n- The gif below shows an `admin` logging in and adding one movie using the wizard feature:\n\n  ![demo-admin](documentation/demo-admin.gif)\n\n- The gif below shows a `user` logging in using his Github account; then he changes his avatar and comment on a movie:\n\n  ![demo-user-github](documentation/demo-user-github.gif)\n\n## Testing movies-api endpoints\n\nWe can manage movies by directly accessing `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`.\n\n### Getting Access Token\n\n- Open a terminal.\n\n- Run the following commands to get the access token:\n  ```\n  ACCESS_TOKEN=\"$(curl -s -X POST \\\n    \"http://localhost:8080/realms/company-services/protocol/openid-connect/token\" \\\n    -H \"Content-Type: application/x-www-form-urlencoded\" \\\n    -d \"username=admin\" \\\n    -d \"password=admin\" \\\n    -d \"grant_type=password\" \\\n    -d \"client_id=movies-app\" | jq -r .access_token)\"\n\n  echo $ACCESS_TOKEN\n  ```\n  \u003e **Note**: In [jwt.io](https://jwt.io), we can decode and verify the `JWT` access token.\n\n### Calling movies-api endpoints using curl\n\n- Trying to add a movie without access token:\n  ```\n  curl -i -X POST \"http://localhost:9080/api/movies\" \\\n    -H \"Content-Type: application/json\" \\\n    -d '{ \"imdbId\": \"tt5580036\", \"title\": \"I, Tonya\", \"director\": \"Craig Gillespie\", \"year\": 2017, \"poster\": \"https://m.media-amazon.com/images/M/MV5BMjI5MDY1NjYzMl5BMl5BanBnXkFtZTgwNjIzNDAxNDM@._V1_SX300.jpg\"}'\n  ```\n\n  It should return:\n  ```\n  HTTP/1.1 401\n  ```\n\n- Trying again to add a movie, now with access token (obtained at [getting-access-token](#getting-access-token)):\n  ```\n  curl -i -X POST \"http://localhost:9080/api/movies\" \\\n    -H \"Authorization: Bearer $ACCESS_TOKEN\" \\\n    -H \"Content-Type: application/json\" \\\n    -d '{ \"imdbId\": \"tt5580036\", \"title\": \"I, Tonya\", \"director\": \"Craig Gillespie\", \"year\": 2017, \"poster\": \"https://m.media-amazon.com/images/M/MV5BMjI5MDY1NjYzMl5BMl5BanBnXkFtZTgwNjIzNDAxNDM@._V1_SX300.jpg\"}'\n  ```\n\n  It should return:\n  ```\n  HTTP/1.1 201\n  {\n    \"imdbId\": \"tt5580036\",\n    \"title\": \"I, Tonya\",\n    \"director\": \"Craig Gillespie\",\n    \"year\": \"2017\",\n    \"poster\": \"https://m.media-amazon.com/images/M/MV5BMjI5MDY1NjYzMl5BMl5BanBnXkFtZTgwNjIzNDAxNDM@._V1_SX300.jpg\",\n    \"comments\": []\n  }\n  ```\n\n- Getting the list of movies. This endpoint does not require access token:\n  ```\n  curl -i http://localhost:9080/api/movies\n  ```\n\n  It should return:\n  ```\n  HTTP/1.1 200\n  [\n    {\n      \"imdbId\": \"tt5580036\",\n      \"title\": \"I, Tonya\",\n      \"director\": \"Craig Gillespie\",\n      \"year\": \"2017\",\n      \"poster\": \"https://m.media-amazon.com/images/M/MV5BMjI5MDY1NjYzMl5BMl5BanBnXkFtZTgwNjIzNDAxNDM@._V1_SX300.jpg\",\n      \"comments\": []\n    }\n  ]\n  ```\n\n### Calling movies-api endpoints using Swagger\n\n- Access `movies-api` Swagger website, http://localhost:9080/swagger-ui.html.\n\n- Click `Authorize` button.\n\n- 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.\n\n- Done! We can now access the secured endpoints.\n\n## Useful Commands\n\n- **MongoDB**\n\n  List all movies:\n  ```\n  docker exec -it mongodb mongosh moviesdb\n  db.movies.find()\n  ```\n  \u003e Type `exit` to exit of MongoDB shell.\n\n## Shutdown\n\n- To stop `movies-api` and `movies-ui`, go to the terminals where they are running and press `Ctrl+C`;\n\n- To stop and remove docker containers, network and volumes, go to a terminal and, inside the `springboot-react-keycloak` root folder, run the command below:\n  ```\n  ./shutdown-environment.sh\n  ```\n\n## How to upgrade movies-ui dependencies to latest version\n\n- In a terminal, make sure you are in the `springboot-react-keycloak/movies-ui` folder;\n\n- Run the following commands:\n  ```\n  npm upgrade\n  npm i -g npm-check-updates\n  ncu -u\n  npm install\n  ```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fivangfr%2Fspringboot-react-keycloak","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fivangfr%2Fspringboot-react-keycloak","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fivangfr%2Fspringboot-react-keycloak/lists"}