The goals of this project are:
- Create a 
Spring Bootapplication that manages books, calledbook-service; - Use 
Keycloakas OpenID Connect provider; - Test using 
Testcontainers; - Explore the utilities and annotations that 
Spring Bootprovides for testing applications. 
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 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] Building a Single Spring Boot App with Keycloak or Okta as IdP: Introduction
 
-   
Spring BootWeb application that manages books.MongoDBis used as storage, and the application's sensitive endpoints (like create, update and delete books) are secured. 
Open a terminal and, inside the springboot-keycloak-mongodb-testcontainers root folder, run the script below
./init-environment.shThere are two ways: running a script or using the Keycloak website
-  
In a terminal, make sure you are inside the
springboot-keycloak-mongodb-testcontainersroot folder -  
Run the following script to configure
Keycloakforbook-serviceapplication./init-keycloak.sh
This script will create:
company-servicesrealm;book-serviceclient;manage_booksclient role;- user with username 
ivan.franchinand password123and with the rolemanage_booksassigned. 
 -  
The
book-serviceclient secret (BOOK_SERVICE_CLIENT_SECRET) is shown at the end of the execution. It will be used in the next step. -  
You can check the configuration in
Keycloakby accessing http://localhost:8080. The credentials areadmin/admin. 
-  
Access http://localhost:8080
 -  
Login with the credentials
Username: admin Password: admin 
- On the left menu, click the dropdown button that contains 
Keycloakand then, clickCreate Realmbutton - Set 
company-servicesto theRealm namefield and clickCreatebutton 
- On the left menu, click 
Authentication - Select 
Required actionstab - Disable 
Verify Profile 
- On the left menu, click 
Clients - Click 
Create clientbutton - In 
General Settings- Set 
book-servicetoClient ID - Click 
Nextbutton 
 - Set 
 - In 
Capability config- Enable 
Client authenticationtoggle switch - Click 
Nextbutton 
 - Enable 
 - In 
Login settingstab- Set 
http://localhost:9080/*toValid redirect URIs - Click 
Savebutton 
 - Set 
 - In 
Credentialstab, you can find the secret generated forbook-service - In 
Rolestab- Click 
Create rolebutton - Set 
manage_bookstoRole Name - Click 
Savebutton 
 - Click 
 
- On the left menu, click 
Users - Click 
Create new userbutton - Set 
ivan.franchintoUsernamefield - Click 
Create - In 
Credentialstab- Click 
Set passwordbutton - Set the value 
123toPasswordandPassword confirmation - Disable the 
Temporarytoggle switch - Click 
Savebutton - Confirm by clicking 
Save passwordbutton 
 - Click 
 - In 
Role Mappingstab- Click 
Assign rolebutton - Click 
Filter by realm rolesdropdown button and selectFilter by clients - Select 
[book-service] manage_booksname and clickAssignbutton 
 - Click 
 
-  
Open a new terminal and navigate to the
springboot-keycloak-mongodb-testcontainersroot folder -  
Run the following command to start the application
./gradlew book-service:clean book-service:bootRun --args='--server.port=9080' 
-  
In a terminal, navigate to the
springboot-keycloak-mongodb-testcontainersroot folder -  
Build Docker Image
./build-docker-images.sh
Environment Variable Description MONGODB_HOSTSpecify host of the Mongodatabase to use (defaultlocalhost)MONGODB_PORTSpecify port of the Mongodatabase to use (default27017)KEYCLOAK_HOSTSpecify host of the Keycloakto use (defaultlocalhost)KEYCLOAK_PORTSpecify port of the Keycloakto use (default8080) -  
Run
book-servicedocker container, joining it to project Docker networkdocker run --rm --name book-service \ -p 9080:8080 \ -e MONGODB_HOST=mongodb \ -e KEYCLOAK_HOST=keycloak \ --network=springboot-keycloak-mongodb-testcontainers-net \ ivanfranchin/book-service:1.0.0
 
-  
In a terminal, create an environment variable that contains the
Client Secretgenerated byKeycloaktobook-serviceat Configure Keycloak stepBOOK_SERVICE_CLIENT_SECRET=...
 -  
When running book-service with Gradle
Run the commands below to get an access token for
ivan.franchinACCESS_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=ivan.franchin" \ -d "password=123" \ -d "grant_type=password" \ -d "client_secret=$BOOK_SERVICE_CLIENT_SECRET" \ -d "client_id=book-service" | jq -r .access_token) echo $ACCESS_TOKEN
 -  
When running book-service as a Docker Container
Run the commands below to get an access token for
ivan.franchinACCESS_TOKEN=$( docker run -t --rm -e CLIENT_SECRET=$BOOK_SERVICE_CLIENT_SECRET --network springboot-keycloak-mongodb-testcontainers-net alpine/curl:latest sh -c ' curl -s -X POST http://keycloak:8080/realms/company-services/protocol/openid-connect/token \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "username=ivan.franchin" \ -d "password=123" \ -d "grant_type=password" \ -d "client_secret=$CLIENT_SECRET" \ -d "client_id=book-service"' | jq -r .access_token) echo $ACCESS_TOKEN
Note: We are running a alpine/curl Docker container and joining it to the project Docker network. By specifying
"keycloak:8080"as host/port, we won't encounter the error related to an invalid token issuer. -  
In jwt.io, you can decode and verify the
JWTaccess token 
-  
In terminal, call the endpoint
GET /api/bookscurl -i http://localhost:9080/api/books
It should return:
HTTP/1.1 200 [] -  
Try to call the endpoint
POST /api/books, without access tokencurl -i -X POST http://localhost:9080/api/books \ -H "Content-Type: application/json" \ -d '{"authorName": "Ivan Franchin", "title": "Java 8", "price": 10.5}'
It should return:
HTTP/1.1 401 -  
Get the Access Token as explained on section Getting Access Token
 -  
Call the endpoint
POST /api/books, now informing the access tokencurl -i -X POST http://localhost:9080/api/books \ -H "Authorization: Bearer $ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{"authorName": "Ivan Franchin", "title": "Java 8", "price": 10.5}'
It should return something like:
HTTP/1.1 201 {"id":"612f4f9438e39e473c4d098b", "authorName":"Ivan Franchin", "title":"Java 8", "price":10.5} 
-  
Click
GET /api/booksto open it. Then, clickTry it outbutton and, finally, clickExecutebutton.It will return a HTTP status code
200and an empty list or a list with some books if you've already added them. -  
Now, let's try to call a secured endpoint without authentication. Click
POST /api/booksto open it. Then, clickTry it outbutton (you can use the default values) and, finally, clickExecutebutton.It will return:
Code: 401 Details: Error: response status is 401 -  
Get the Access Token as explained on section Getting Access Token
 -  
Copy the token generated and go back to
Swagger -  
Click the
Authorizebutton and paste the access token in theValuefield. Then, clickAuthorizeand, to finalize, clickClose -  
Go to
POST /api/books, clickTry it outand, finally, clickExecutebutton.It should return something like:
HTTP/1.1 201 { "id": "612f502f38e39e473c4d098c", "authorName": "Ivan Franchin", "title": "SpringBoot", "price": 10.5 } 
-  
MongoDB
List books
docker exec -it mongodb mongosh bookdb db.books.find()
Type
exitto get out of MongoDB shell 
- To stop 
book-service, go to the terminal where the application is running and pressCtrl+C; - To stop the Docker containers started using the 
./init-environment.shscript, make sure you are inspringboot-keycloak-mongodb-testcontainersand run the script below:./shutdown-environment.sh
 
To remove the Docker image created by this project, go to a terminal and, inside the springboot-keycloak-mongodb-testcontainers root folder, run the following script:
./remove-docker-images.sh-  
In a terminal and inside the
springboot-keycloak-mongodb-testcontainersroot folder, run the command below to run unit and integration tests./gradlew book-service:clean book-service:assemble \ book-service:cleanTest \ book-service:test \ book-service:integrationTest
Note: During integration tests,
Testcontainerswill automatically startMongoDBandKeycloakcontainers before the tests begin and shut them down when the tests finish. -  
From the
springboot-keycloak-mongodb-testcontainersroot folder, the Unit Testing Report can be found at:book-service/build/reports/tests/test/index.html -  
From the
springboot-keycloak-mongodb-testcontainersroot folder, the Integration Testing Report can be found at:book-service/build/reports/tests/integrationTest/index.html 
