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 when 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
springboot-keycloak-mongodb-testcontainersroot folder rundocker compose up -d -
Wait for
keycloakandmongodbDocker containers to be up and running. To check it, rundocker compose ps
There are two ways: running a script or using Keycloak website
-
In a terminal, make sure you are in
springboot-keycloak-mongodb-testcontainersroot folder -
Run the following script to configure
Keycloakforbook-serviceapplication./init-keycloak.shThis script creates:
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/admin
-
Login with the credentials
Username: admin Password: admin
- On the left menu, click the dropdown button that contains
Masterand then, clickCreate Realmbutton - Set
company-servicesto theRealm namefield and clickCreatebutton
- 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
Savebutton
- Enable
- In
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
Save - In
Credentialstab- Click
Set passwordbutton - Set the value
123toPasswordandPassword confirmation - Disable the
Temporaryfield toggle switch - Click
Savebutton - Confirm by clicking
Save Passwordbutton
- Click
- In
Role Mappingstab- Click
Assign rolebutton - Click
Filter by Origindropdown button and selectbook-service - Select
manage_booksrole and clickAssignbutton
- Click
-
Open a new terminal and navigate to
springboot-keycloak-mongodb-testcontainersroot folder -
Run the following command to start the application
./gradlew book-service:clean book-service:bootRun --args='--server.port=9080' -
The application Swagger URL is http://localhost:9080/swagger-ui.html
-
Open a terminal and make sure you are in
springboot-keycloak-mongodb-testcontainersroot folder -
Create an environment variable that contains the
Client Secretgenerated byKeycloaktobook-serviceat Configure Keycloak stepBOOK_SERVICE_CLIENT_SECRET=... -
Run the commands below to get an access token for
ivan.franchinACCESS_TOKEN=$(./get-access-token.sh $BOOK_SERVICE_CLIENT_SECRET) && echo $ACCESS_TOKENNote: In jwt.io, you can decode and verify the
JWTaccess token -
The access token has a default expiration time of
5 minutes
-
In terminal, call the endpoint
GET /api/bookscurl -i http://localhost:9080/api/booksIt 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 -
If you do not have the access token stored in
ACCESS_TOKENenvironment variable, get it by following the steps describe at 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 at 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 }
-
In a terminal, navigate to
springboot-keycloak-mongodb-testcontainersroot folder -
Build Docker Image
./docker-build.shEnvironment 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 docker compose networkdocker run --rm --name book-service \ -p 9080:8080 \ -e MONGODB_HOST=mongodb \ -e KEYCLOAK_HOST=keycloak \ --network=springboot-keycloak-mongodb-testcontainers_default \ ivanfranchin/book-service:1.0.0 -
Open a new terminal and create an environment variable that contains the
Client Secretgenerated byKeycloakBOOK_SERVICE_CLIENT_SECRET=... -
In order to get the access token from
Keycloak, run the following commandsACCESS_TOKEN=$(./get-access-token.sh $BOOK_SERVICE_CLIENT_SECRET "keycloak:8080") && echo $ACCESS_TOKENNote 1: the
"keycloak:8080"string is informed in the second argument of the script. It changes"localhost:8080"host/port inside the script. This way, we won't have the error complaining about an invalid token due to an invalid token issuer.Note 2: In jwt.io, you can decode and verify the
JWTaccess token -
Test using cURL or using Swagger as explained above
-
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 and remove docker compose containers, networks and volumes, make sure you are in
springboot-keycloak-mongodb-testcontainersand rundocker compose down -v
To remove the Docker image created by this project, go to a terminal and, inside springboot-keycloak-mongodb-testcontainers root folder, run the following script
./remove-docker-images.sh -
In a terminal and inside
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:integrationTestNote: During integration tests,
Testcontainerswill start automaticallyMongoDBandKeycloakcontainers before the tests begin and shuts them down when the tests finish. -
From
springboot-keycloak-mongodb-testcontainersroot folder, Unit Testing Report can be found atbook-service/build/reports/tests/test/index.html -
From
springboot-keycloak-mongodb-testcontainersroot folder, Integration Testing Report can be found atbook-service/build/reports/tests/integrationTest/index.html

