1. Introduction

Keycloak is an open-source identity and access management solution aimed at modern applications and services. By default, Keycloak uses files or an embedded H2 database ot store configuration data. The storage is located inside a container and is not persistent when container is removed or recreated. To ensure data persistence, it is recommended to configure Keycloak to use an external database.

2. Database

Create a user keycloak and database keycloak owning by that user.

2.1. Local database

If there is a need to reuse local database already running on local machine directly (without docker image), an configuration update is required.

I file postgresql.conf update the listen_addresses. Use either * (be sure that firewall is configured correctly) or the specific interface.:

listen_addresses = '*'

Adjust the pg_hba.conf file to allow connections from docker container.

# Docker Internal Network Access
# Adjust the IP range if your Docker setup uses a non-standard one (if needed)
host    all             all             172.17.0.0/16           scram-sha-256

Restart PostgreSQL service to apply changes.

You can test setup by running test PostgreSQL container

docker run -ti --rm postgres:18 psql -h host.docker.internal -p 5432 -U keycloak -d keycloak

The command should ask for password. Enter password na verify that connection is established.

In case of wrong configuration various error messages may be displayed.

2.2. Containerized database

In case of containerized database is the configuration straight forward. Container name can be used for DNS resolution.

3. Keycloak configuration

Then the keycloak (in development mode) can by run by following command:

docker run -p 18080:8080 \
  --name keycloak \
  -e KEYCLOAK_ADMIN=admin \
  -e KEYCLOAK_ADMIN_PASSWORD=admin \
  -e KC_DB=postgres \
  -e KC_DB_URL=jdbc:postgresql://host.docker.internal:5432/keycloak \
  -e KC_DB_USERNAME=keycloak \
  -e KC_DB_PASSWORD=your_secure_password \
  quay.io/keycloak/keycloak:26.4.7 \
  start-dev

Now should be the keycloak accessible on port 18080 on localhost.

4. Keycloak setup

4.1. Realm

Create new realm pdm for PDM project . More instruction can be found on youtube - Create and configure realm

4.1.1. Admin user

Create admin user for the realm to be able manage users. Go to Users  Add user and create new user with following configuration: * Username: kc-admin (it must be name which does not conflict with existing users of PDM.control) * Set the rest according to your needs.

Set password for the user. Go to Users  kc-admin  Credentials and set new password. Set temporary to off and click Save.

Add admin role to the user. Go to Users  kc-admin  Role Mappings  Assign role  Client Roles. Assign role realm-admin, user-admin to this user.

4.1.2. Make attributes visible

Open Realm settings  User profile  Attributes Group and click Create attribute group. Add following group

  • Name: pdm-user

  • Display mane: PDM user

  • Description: Attributes of PDM.cloud users

Then add out two attributes

Open Realm settings  User profile and click Create attribute. Add following attributes:

  • Time zone

    • Name: timeZone

    • Display name: Users’s time zone

    • Multivalued: off

    • Default value: <empty>

    • Attribute group: pdm-user

    • Required field: on

    • Required forRequired for: Both users and admins

    • Required when: Always

    • Who can edit: [X] User [X] Admin

    • Who can view: [X] User [X] Admin

  • Areas

    • Name: areas

    • Display name: Areas to control

    • Multivalued: on

    • Default value: <empty>

    • Attribute group: pdm-user

    • Required field: off

    • Required forRequired for: Both users and admins

    • Required when: Always

    • Who can edit: [ ] User [X] Admin

    • Who can view: [X] User [X] Admin

    • Annotations:

      • inputType: text

4.2. Client scope

Create a client scope to propagate custom attributes to JWT. Go to Client scopes and create new scope pdm-user with following configuration:

4.2.1. Settings

  • Name: pdm-user

  • Description: Defines parts of the project accessible by the user

  • Type: None

  • Include in token scope: off

  • Leave default the rest of the options.

4.2.2. Mappers

Add mapper for time_zone attribute

Open Client scopes  pdm-user  Mappers  Add mapper  Configure new mapper / By Configuration  User Attribute.

  • Name: timeZone

  • User Attribute: time_zone

  • Token Claim Name: time_zone

  • Claim JSON Type: String

  • Set following switches to ON:

    • Add to ID token

    • Add to access token

    • Add to userinfo

    • _Add to token introspection _

  • Set the rest to OFF.

Add mapper for areas

  • Name: areas

  • User Attribute: areas

  • Token Claim Name: areas

  • Claim JSON Type: String

  • Set following switches to ON:

    • Add to ID token

    • Add to access token

    • Add to userinfo

    • Add to token introspection

    • Multivalued

  • Set the rest to OFF.

4.3. Clients

4.3.1. UI client

Create a new client pdm-web for PDM.control UI application.

More info - youtube - Create client. Read Explanation of client options. Additionally add just created scope. menu: Clients[pdm-web > Client Scopes > Add Client scope > Default Client Scopes > {pdm-user} > Add > Default].

Create test user e.g. realm-admin with password admin to test token retrieval.
curl --location 'https://auth.pdm-dev.de/realms/pdm-stage-jar/protocol/openid-connect/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=password' \
--data-urlencode 'client_id=pdm-web' \
--data-urlencode 'username=realm-admin' \
--data-urlencode 'password=admin'
You need temporarily allow direct access grants to test the token retrieval.

The token should contains also time_zone and areas attributes.

Remove unnecessary claims

Remove unnecessary claims from JWT to make it shorter. Unnecessary claim are user personal data. It is possible to load them from http://kyecloak/realms/{realm}/protocol/openid-connect/userinfo See request_user_info.py to see how it works.

Open client Clients  pdm-web  Client scopes

4.3.2. Backend client

Create a client with higher privileges to allow backend services query / manage other users from this realm.

Open Clients  Create client and create new client. Read Explanation of client options. Then use following configuration:

General Settings

  • Client ID: pdm-control

  • Name: Internal backend client

  • Description: Client for backend services for querying and managing users

  • Always display in UI: Off

Click button Next.

Select following settings:

  • Client authentication: ON

  • Authentication flow  Service accounts roles: checked

  • Authentication flow  Direct access grants: checked. This is required to be able emulate basic authentication for external API. It allows to exchange username and password for access token without need to log in to Keycloak UI. It can be removed after migration to Oauth2 method is completed. However this client is not publicly accessible, therefore such permission should not cause security issues.

Leave or set OFF or unchecked the rest of the options.

Click button Next.

Leave everything empty.

Click button Save.

To get the 'access token' open Clients  pdm-control  Credentials  Client Secret and copy the Secret value.

Alternatively it is possible to set lifespan of backend token shorter then standard one. See https://youtu.be/ZQ1KApBJbR8

4.3.3. Explanation of client options

AI generated. Please review and adjust the content if needed. ===== Capability config

Client authentication: ON

Meaning: This makes the client "Confidential." It generates a Client Secret (a password for your internal backend Java app).

Without this (turning off), the client is "public" (like a mobile app) and cannot safely hold the permissions needed to query the User API. Client always requires a user to log in.

Authorization: Off

Meaning: This refers to Keycloak’s "Fine-Grained Authorization Services" (complex policies/permissions). You don’t need this for a simple user lookup.

Service accounts roles: ON

Meaning: It allows the client to act as its own "user." It creates a background service account that stays active without a human logging in. You can assign the specific permissions to this specific service account.

Table 1. Authentication flows
Flow Meaning Should you use it?

Standard Flow

Used for browser-based logins (redirects to Keycloak login page).

Only if your Java app has a UI where users log in.

Direct Access Grants

Allows exchanging a username + password directly for a token.

No. This is less secure and bypasses MFA.

Implicit Flow

"An old, insecure flow for legacy JavaScript apps."

No. (Deprecated in modern security).

Standard Token Exchange

"Allows one client to ""swap"" its token for a token for another client."

No. Too complex for your current needs.

OAuth 2.0 Device Auth

Used for devices with no browser (like Smart TVs).

No.

OIDC CIBA Grant

"Used for ""out-of-band"" auth (e.g., approving a login on a phone app)."

No.

Service accounts roles

This refers to Keycloak’s "Fine-Grained Authorization Services" (complex policies/permissions). You don’t need this for a simple user lookup.

Yes

5. Additional information sources

6. Setup for development and system test

Do not use it in production.

The setup described below was not reviewed by any security expert and may contains some security flows. Always contact our security experts for optimal settings.

Because some customers did not entered the e-mail address the keycloak import of such a record fails. To mitigate the problem we provide the email address of administrator parking-helpdesk@rtb-bl.de.

However keycloak does not support duplicated email addresses. To allow this got to

To save the file, select File  Save.

Select Realm Settings  Login  Email settings and set

  • Email as username: off

  • Login with email: off

  • Duplicate emails: on

Important tips:

  • Remember to set Client  pdm_ui  Settings  Home URL.

Without this it will not be possible to return from profile setting back to application.

7. Import existing users

First create an realm administrator user. Select a user name which does not conflict with existing users of PDM.control which will be imported.

Be sure that it has role realm-admin assigned. Otherwise he will not be able to see dashboard and manage settings.

  1. In Keycloak, fine-grained admin permissions aren’t usually global "realm roles"; they are often linked to the realm-management client. Ensure you have done the following:

  2. Go to the user kc-admin.

  3. Go to the Role Mapping tab.

  4. Click Assign Role and filter by Client roles.

  5. Search for the Client ID named realm-management.

  6. Assign roles like realm-admin (full power) or the specific ones you mentioned (manage-users, etc.).

Then login using one of the following URLs:

Table 2. Log-in URLS

Goal

URL Path

Super Admin (Global)

{keycloak-url}/admin/master/console/

Realm Admin (Your User)

{keycloak-url}/admin/{your-realm}/console/

Account Console (User Profile)

{keycloak-url}/realms/{your-realm}/account/

Use kc-migrator tool to import existing users from PDM.control database to Keycloak. Read the documentation of the tool for more details.

8. Email

Do not forget to set up email server in Keycloak to be able to send password reset emails and other notifications. Go to Realm Settings  Email and set up email server.