Keycloak Database User Federation

Keycloak uses a local database by default to manage users. However, many organizations have existing user credentials available in a relational database. This article will teach you how to use Keycloak’s User Storage SPI to federate users from a PostgreSQL Database.

Concept of User Federation

User Federation in Keycloak refers to the ability to connect to external user stores, such as LDAP servers, Active Directory (AD), or custom databases. Keycloak acts as an intermediary, handling authentication requests and retrieving user information from external sources without migrating users and their credentials.
This approach allows centralized management of user identities across different realms or systems.
Out of the box, Keycloak supports LDAP and SAML Federation. This article discusses how to federate users from a relational Database such as PostgreSQL. With some changes in the configuration, you can easily adapt to another Database Provider.
In order to perform Database Federation we will leverage Keycloak’s User Storage SPI (Service Provider Interface) that allows developers to write extensions for connecting to other storages.

Let’s see how to do it in practice.

Setting up the Keycloak Project

To build the Custom DB Provider I will extend an existing GitHub useful project from Tilman Kranz. I have applied some changes to automate the database set up. At the end of this article you will find the link to the Source code for it.

Within the project you will find the following Components:

1) Entity Classes

The following Entity Classes are mapping the Storage Schema where Users are available for each Client and Realm.

  • ClientRoleEntity : Entity mapping the Table client_roles
  • RealmRoleEntity Entity mapping the Table realm_roles
  • UserEntity: Entity mapping the Table users

2) UserStorageProvider Class

Provider classes do all the heavy lifting of user lookup from the storage provider and other user operations. They must implement the org.keycloak.storage.UserStorageProvider .  Additionally, you need to implement a set of capability interfaces methods for locating or managing users. (Ex: UserQueryProvider, UserLookupProvider etc). To create a UserStorageProvider instance, you need to implement the UserStorageProviderFactory.

3) UserAdapter

This Class extends an utility class called org.keycloak.storage.adapter.AbstractUserAdapterFederatedStorage. This class handles most of the UserModel methods, except for the username-related ones, which it delegates to an external user data store. If needed, you can customize and override specific methods to work with your external data store.

Overall, this is the database schema which contains the relations between users, clients, roles, and realms.

keycloak database user federation

To build the Project you can run from the command line:

mvn install

Install the Test Provider

Next, we will install the custom provider in Keycloak. To do that, copy the JAR file from the previous build into the providers folder of your Keycloak distribution:

cp target/rdbms-federation.jar /path/keycloak-25.0.4/providers

Add the Database configuration

The newest Keycloak distributions rely on Quarkus as Runtime engine. ( More details in this article: Getting started with Keycloak powered by Quarkus )

Therefore, to configure Keycloak’s Datasource to use a PostgreSQL database copy the following quarkus.properties to the  conf folder of Keycloak.

quarkus.datasource.user-store.db-kind=postgresql
quarkus.datasource.user-store.username=postgres
quarkus.datasource.user-store.password=postgres
quarkus.datasource.user-store.jdbc.url=jdbc:postgresql://localhost:5432/userdb
quarkus.datasource.user-store.jdbc.acquisition-timeout=30
cp conf/qauarkus.properties /path/keycloak-25.0.4/conf

Finally, to set up the Database and the Schema, I have added a docker-compose.yml file in the project which, out of the box, prepares your Database environment.

services:
  postgres:
    image: postgres
    container_name: postgres-keycloak
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: userdb
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql

volumes:
  postgres_data:

You can run it as follows:

docker-compose up

The docker-compose log should print on the Console the execution of the init SQL script. You can verify that the Database tables actually exist by logging into the Container:

# su postgres
postgres@1972a6179a77:/$ psql
psql (16.4 (Debian 16.4-1.pgdg120+1))
Type "help" for help.

postgres=# \c userdb
You are now connected to database "userdb" as user "postgres".
userdb=# \dt;
                List of relations
 Schema |         Name          | Type  | Owner  
--------+-----------------------+-------+--------
 public | client_roles          | table | userdb
 public | realm_roles           | table | userdb
 public | users                 | table | userdb
 public | users_to_client_roles | table | userdb
 public | users_to_realm_roles  | table | userdb

The init.sql script included a single user with the following credentials:

  • Username: fmarchioni
  • Password: secret (hashed with SHA-512)

Take note of the credentials since we will use them to test our application.

Configuring the Keycloak Realm

In the following section we will show how to set up a Keycloak example Realm from a standard distribution. If you want to use the Keycloak Docker image we recommend checking this article: How to run Keycloak with Docker

Firstly, rebuild your Keycloak distribution so that you will be able to find the new provider

./kc.sh build

Then, start Keycloak and verify that the Console does not contain any Connection errors to the Database:

kc.sh start-dev

Next, login to the Keycloak Admin Console with the admin Credentials and perform the following steps:

Create a new Realm “db-federation”:

keycloak custom provider example

Add the Database Provider to the Realm. To do that, select “User Federation” and Add “rdbms-federation provider”

keycloak database provider

Create an OIDC Client “testclient” with Redirect URI to “http://localhost:8180” ( where our application will run):

keycloak example postgresql

Next, create the Test Realm Role

Then, create a role “testrole” in realm “master”:

keycloak create custom provider

Create the Test Client Role

Create a role “admin” in client “testclient” using the ID value from the previous command:

keycloak tutorial

Finally, from the Client UI download the Adapter Config we will use in our application:

{
  "realm": "db-federation",
  "auth-server-url": "http://localhost:8080/",
  "ssl-required": "external",
  "resource": "testclient",
  "public-client": true,
  "verify-token-audience": true,
  "use-resource-role-mappings": true,
  "confidential-port": 0
}

Testing the Database Federation with an Application

You can test an example application which uses a Servlet and an HttpMethodConstraint that requires an “admin” Role:

@WebServlet("/secured")
@ServletSecurity(httpMethodConstraints = { @HttpMethodConstraint(value = "GET", rolesAllowed = { "admin" }) })
public class SecuredServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        try (PrintWriter writer = resp.getWriter()) {
            writer.println("<html>");
            writer.println("  <head><title>Secured Servlet</title></head>");
            writer.println("  <body>");
            writer.println("    <h1>Secured Servlet</h1>");
            writer.println("    <p>");
            writer.print(" Current Principal '");
            Principal user = req.getUserPrincipal();
            writer.print(user != null ? user.getName() : "NO AUTHENTICATED USER");
            writer.print("'");
            writer.println("    </p>");
            writer.println("  </body>");
            writer.println("</html>");
        }
    }

}

You will need to include the oidc.json file in the WEB-INF folder of your application:

├───src
│   └───main
│       ├───java
│       │   └───com
│       │       └───mastertheboss
│       │           └───servlet
│       │                   SecuredServlet.java
│       │
│       └───webapp
│           └───WEB-INF
│                   oidc.json
│                   web.xml

Finally, the web.xml needs to set OIDC as the Login Configuration:

<login-config>
        <auth-method>OIDC</auth-method>
</login-config>

Start WildFly with an offset ( for example 100) in order to avoid conflicts with Keycloak.

./standalone.sh  -Djboss.socket.binding.port-offset=100

Then, request the /secured Servlet at http://localhost:8180/db-provider/secured :

You will be redirected to Keycloak login for the DB Federation:

keycloak db federation example

Enter the credentials and verify that you can access the Secured Servlet:

Secured Servlet
Current Principal 'f:52e7998d-4f5d-46a6-aab0-7832c4c6cb4a:1'

Source code

The Keycloak Database Provider example is available in this repository: https://github.com/fmarchioni/keycloak-user-storage-test

The source code for the Jakarta EE project is available here: https://github.com/fmarchioni/mastertheboss/tree/master/keycloak/db-provider

Conclusion

This article was a step-by-step guide through the creation of a Keycloak DB Provider that will let you authenticate with a PostgreSQL database. We have gone through the steps to load the DBProvider in a Keycloak Realm and finally we have tested the application on WildFly by exporting the Client Adapter JSON configuration.