Using role based access for secure endpoints and allowing anonymous access for public ones
Securing an application with Keycloak is relatively easy. Having both secured and public endpoints is not so straightforward. Here you will see how to achieve that in a few easy steps.
This post demonstrates the minimal set of configurations required to secure the REST endpoints of a Spring Boot application using Keycloak and how to allow anonymous access to the public endpoints.
Keycloak provides Identity and Access Management services. It’s open source and is compliant with the OpenID Connect, OAuth 2.0, and SAML protocols.
Some of its key features are:
- Single-Sign On
- Identity Brokering and Social Login
- User Federation
- Client Adapters
- Admin Console
- Account Management console
For more information check out Keycloak’s official page.
Setting up a Keycloak server
Docker will be used for the deployment of a Keycloak server.
If you’re not familiar with it you can refer to the standard way specified in the documentation which is pretty straightforward as well. You’ll just have to create an admin user separately.
The following command does a few things:
- Starts the Keycloak server in the background;
- Exposes the server on port 8081 on the host machine;
- Creates an initial admin user with username `admin` and password `admin`
- Specifies that Keycloak should use its embedded H2 database. H2 is the default DB_VENDOR value. The purpose of specifying it here is to illustrate that a database is used to store configurations, user information, etc. Supported databases are H2, MySQL, PostgreSQL, MariaDB and Oracle – for more details please check Keycloak documentation.
docker run -d --name keycloak --rm -p 8081:8080 -e KEYCLOAK_USER=admin -e KEYCLOAK_PASSWORD=admin -e DB_VENDOR=h2 jboss/keycloak
To verify that Keycloak container is running execute `docker ps`. The container status should be `UP`:
95dd64a63178 jboss/keycloak "/opt/jboss/tools/do..." 5 seconds ago Up 4 seconds 0.0.0.0:8081->8080/tcp keycloak
You should now be able to open Keycloak admin UI on http://localhost:8081 and you can login with admin:admin in the master realm.
Configuring Keycloak
Keycloak can be configured entirely through its UI but in order to allow the process to be automated we are going to use the Keycloak Admin REST API . We will send a request to the REST API with a JSON file, containing the keycloak configuration, in the request body.
Bellow we describe the minimal set of objects that you have to create in Keycloak:
- Realm – A realm manages a set of users, credentials, roles and groups. A user belongs to and logs into a realm. Realms are isolated from one another and can only manage and authenticate the users that they control.
In this example we will define the user roles on the realm level rather than the client level. Realm roles can be assigned to any user belonging to any client.
- Client – Clients are entities that can request Keycloak to authenticate a user. Most often, clients are applications and services that want to use Keycloak to secure themselves and provide a single sign-on solution. Clients can also be entities that just want to request identity information or an access token so that they can securely invoke other services on the network that are secured by Keycloak.
The client will correspond to our Spring Boot application which we aim to secure.
- Role – Roles identify a type or category of user. `Admin`, `user`, `manager` and `employee` are all typical roles that may exist in an organization. Applications often assign access and permissions to specific roles rather than individual users as dealing with users can be too fine grained and hard to manage.
- User – Users are entities that are able to log into your system. They can have attributes associated with themselves like email, username, address, phone number, and birthday. They can be assigned group membership and have specific roles assigned to them.
This is the JSON configuration that we will be using:
{ "realm": "spring-keycloak", "enabled": true, "clients": [ { "clientId": "resource-service", "enabled": true, "secret": "secret", "directAccessGrantsEnabled": true } ], "roles": { "realm": [ { "name": "authenticated-user", "description": "Authenticated user privileges" } ] }, "users": [ { "username": "Tom", "enabled": true, "credentials": [ { "type": "password", "value": "password" } ], "realmRoles": [ "authenticated-user" ] } ] }
The configuration is pretty straightforward there are only two things to note here:
- We assign `authenticated-user` role to our test user – Tom;
- We set the `directAccessGrantsEnabled` to true which gives the client direct access to the user credentials and enables it to exchange them for access token. This is the equivalent of OAuth2 Password Grant
The following script configures Keycloak:
#!/usr/bin/env bash # Get Access token # In the request we provide: # 1. Тhe `admin-cli` client which is a public client created by default; # 2. The username and password of the user we created during the initialization of the Keycloak server # 3. Password as grant type json=$(curl -d "client_id=admin-cli" -d "username=admin" -d "password=admin" -d "grant_type=password" "http://localhost:8081/auth/realms/master/protocol/openid-connect/token") && token=$(echo $json | sed "s/{.*"access_token":"([^"]*).*}/1/g") && echo "token = $token" #Configure Keycloak # In the request we provide: # 1. `application/json` as Content type; # 2. The Access token received as response from the previous request # 3. The name of the file in which the JSON configuration is stored curl -X POST -H "Content-Type: application/json" -H "Authorization: bearer $token" --data "@realm-configuration.json" "http://localhost:8081/auth/admin/realms"
You can verify that the configuration succeeded from the Keycloak UI.

Spring Boot application
Our spring Boot application has two endpoints /public and /protected. All endpoints will be secured by default but we will allow anonymous access to the /public one. This is how the Controller looks like:
@RestController public class ResourceController { @GetMapping(value = "/public") public ResponseEntity<String> getPublicResource() { return ResponseEntity.ok("This is a public resource"); } @GetMapping(value = "/protected") public ResponseEntity<String> getProtectedResource() { return ResponseEntity.ok("This is a protected resource"); } }
In order to integrate Keycloak with our application we need the Keycloak Spring Boot adapter JAR.
https://gitlab.com/datastork-examples/spring-keycloak-example/blob/master/build.gradle
dependencyManagement { imports { mavenBom "org.keycloak.bom:keycloak-adapter-bom:6.0.1" } } dependencies { implementation "org.keycloak:keycloak-spring-boot-starter" }
And then we need to configure the application:
https://gitlab.com/datastork-examples/spring-keycloak-example/blob/master/src/main/resources/application.yml
keycloak: realm: spring-keycloak #the name of the realm auth-server-url: http://localhost:8081/auth #Keycloak server endpoint ssl-required: external #localhost and private IPs can access without HTTPS resource: resource-service #the client credentials: secret: secret #the client secret bearer-only: true #do not redirect to login page securityConstraints[0]: securityCollections[0]: name: public endpoints patterns[0]: /public/* #public endpoint; no role is associated with it securityConstraints[1]: authRoles[0]: authenticated-user #user must have `authenticated-user` role to access the resource securityCollections[0]: name: protected endpoints patterns[0]: /* #secure all endpoints by default
Note that the `/public` endpoint does not have a role associated with it and therefore anonymous access to it is allowed. The `authenticates-user` role is associated with all other endpoints which will require the one accessing them to have the `authenticates-user` role.
Testing public and private endpoints:
- Public endpoint
curl -X GET http://localhost:8080/public
2. Private endpoint:
First get an Access token:
In the request we should specify:
- `resource-service` as client id
- `secret` as client secret
- `Tom` as username
- `password` as password
- `password` as grant type
All of the arguments specified above (except grant type) are the Keycloak entities we created during the configuration step.
curl -d "client_id=resource-service" -d "client_secret=secret" -d "username=Tom" -d "password=password" -d "grant_type=password" "http://localhost:8081/auth/realms/spring-keycloak/protocol/openid-connect/token"
Use Access token received as response from previous request.
curl -X GET http://localhost:8080/protected -H "Authorization: Bearer eyJhbGciOiJSUzI..."
Should receive a response similar to this:
% Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 28 100 28 0 0 28 0 0:00:01 --:--:-- 0:00:01 28000This is a protected resource
Conclusion
In this post we’ve seen how to deploy and configure a Keycloak server, how to secure all endpoints by default of a Spring Boot REST application with Keycloak and how to allow anonymous access to some endpoints. This way you can be sure that you can add any number of new endpoints and they will be secured. Publicly available will be only those explicitly exposed.
The code can be found here.