Skip to content

[#50] Setup keycloak#162

Draft
omargoher wants to merge 1 commit into
mnemosyne-systems:mainfrom
omargoher:keycloak-migration
Draft

[#50] Setup keycloak#162
omargoher wants to merge 1 commit into
mnemosyne-systems:mainfrom
omargoher:keycloak-migration

Conversation

@omargoher

Copy link
Copy Markdown

Summary

This is the first phase of the Keycloak migration.

The PR introduces Keycloak infrastructure, realm generation, and backend OIDC configuration.

i added Keycloak service in docker-compose.yml.

and to load Keycloak configuration: created keycloak-realm.template.json, .env-keycloak.example
and generate_realm.py script to generate a project-specific keycloak-realm.json
this avoids changing keycloak-realm.json manually and allows configuration changes through .env-keycloak.

i also added OIDC configuration in src/backend/main/resources/application.properties
and made /api/* endpoints private.

all requests to /api/* now require a valid JWT token in the Authorization header, so the current cookie-based auth no longer works for protected APIs.

How to start

  1. create your own copy of .env-keycloak.example
cp .env-keycloak.example .env-keycloak
  1. add your configuration to .env-keycloak

  2. generate the realm file

python generate_realm.py
  1. run docker compose
docker compose up --build

@jesperpedersen jesperpedersen self-requested a review May 13, 2026 02:37
@jesperpedersen jesperpedersen added the feature A new feature label May 13, 2026
@jesperpedersen

Copy link
Copy Markdown
Contributor

@omargoher Remember the authors file, and license header

@jesperpedersen

Copy link
Copy Markdown
Contributor

@omargoher We will keep this as draft until everything is in place. Then take it out of draft mode, and PTAL me
@trxvorr Cc:

@omargoher omargoher force-pushed the keycloak-migration branch 4 times, most recently from 8d9c649 to 4434cbe Compare May 19, 2026 10:51
@omargoher

omargoher commented May 19, 2026

Copy link
Copy Markdown
Author

@trxvorr

Migrate cookie-based auth to Keycloak OIDC

Replace the custom cookie session authentication system with Keycloak
OIDC bearer token authentication across all resources

What changed

Replace custom cookie session authentication with Keycloak OIDC bearer
token authentication across all resources.

Changes:
New utilities

  • CurrentUser — request-scoped CDI bean that resolves the current DB
    user from the Keycloak JWT principal, cached once per request
  • UserProvisioningService — JIT provisioning on first login; creates
    or syncs local users from Keycloak claims, with email fallback for
    users migrated before Keycloak was introduced

Backend resources

  • Removed @CookieParam + AuthHelper.findUser() from all resources
  • Replaced manual requireX() guards with declarative @RolesAllowed
  • Added keycloakId field to User entity for principal linking and password be nullable

Infrastructure

  • Configured quarkus-oidc in application.properties with role claim
    mapping from realm_access/roles
  • Added Keycloak realm config and updated docker-compose.yml

Breaking change

Cookie-based sessions no longer work. All clients must send:
Authorization: Bearer <token>

React frontend is not yet updated and will not work until the frontend
auth layer is migrated in a follow-up PR.


How to test

Note: should Apply how to start section in first msg

Two helper scripts are provided under keycloak/:

1. Create a Keycloak user

./keycloak/create-user.sh <username> <email> <password> <role> <firstName> <lastName>

# examples
./keycloak/create-user.sh admin    admin@mnemosyne-systems.ai    admin    admin    System  Administrator
./keycloak/create-user.sh user1    user1@mnemosyne-systems.ai    user1    user     John    Doe
./keycloak/create-user.sh support1 support1@mnemosyne-systems.ai support1 support  Sarah   Johnson

2. Get a JWT token

./keycloak/login.sh <username> <password>

# example
./keycloak/login.sh admin admin

3. Call any endpoint

TOKEN=$(./keycloak/login.sh user1 user1)

curl -s "http://localhost:8080/api/user/tickets" \
  -H "Authorization: Bearer $TOKEN" | jq .

Role → endpoint mapping

Role Example endpoint
admin GET /api/admin/users
support GET /api/support/tickets
superuser GET /api/superuser/tickets
tam GET /api/user/tickets
user GET /api/user/tickets
any / none GET /api/app/session

@jesperpedersen

Copy link
Copy Markdown
Contributor

@omargoher Please, rebase and resolve conflicts such that we can review

@omargoher omargoher force-pushed the keycloak-migration branch from 4434cbe to f2211f4 Compare May 20, 2026 11:28
@omargoher

Copy link
Copy Markdown
Author

@jesperpedersen Conflicts resolved and branch rebased successfully.

@jesperpedersen

Copy link
Copy Markdown
Contributor

@omargoher See CI

@omargoher

Copy link
Copy Markdown
Author

@jesperpedersen Sorry, I forgot to run the tests before pushing. Some resource tests are currently failing. I will fix tests and push my changes.

… (backend + tests)

Replace custom cookie session authentication with Keycloak OIDC bearer
token authentication across all resources, and update the full test
suite to work without a running Keycloak instance.

Changes:
- Add CurrentUser bean for request-scoped user resolution via JWT
- Add UserProvisioningService for JIT user provisioning on first login
- Replace @CookieParam + AuthHelper.findUser() with SecurityIdentity
- Replace manual requireX() guards with @RolesAllowed annotations
- Add keycloakId field to User entity for principal linking
- Configure OIDC in application.properties with role claim mapping
- Add Keycloak realm configuration and docker-compose setup

Test changes:
- Remove login() and cookie-based auth from AccessTestSupport
- Remove password parameter from ensureUser() — Keycloak owns passwords
- Replace .cookie(AUTH_COOKIE) with @testsecurity + @JwtSecurity on
  every test method across all test classes
- Disable real Keycloak in test profile using quarkus.oidc.enabled=false

Breaking change: cookie-based sessions no longer work; clients must
send Authorization: Bearer <token> header on all protected requests.
@omargoher omargoher force-pushed the keycloak-migration branch from f2211f4 to e98e684 Compare May 23, 2026 11:50
@omargoher

Copy link
Copy Markdown
Author

@jesperpedersen Tests are now fixed.

@jesperpedersen

Copy link
Copy Markdown
Contributor

@omargoher We need to move the keycloak stuff to /contrib/keycloak/. Also I don't like the @PathParam - we shouldn't have parameters visible in the URL - its session or cookie based

@omargoher

omargoher commented May 23, 2026

Copy link
Copy Markdown
Author

@jesperpedersen

Also I don't like the @PathParam - we shouldn't have parameters visible in the URL - its session or cookie based

I want to know more details about why we should do this. Using parameters in the URL follow REST best practices !

@jesperpedersen

Copy link
Copy Markdown
Contributor

@omargoher Parameters in the URL leaks the data model to the user. It also make it more difficult to make precise bookmarks. So, REST URLs is a no-go

@jesperpedersen

Copy link
Copy Markdown
Contributor

@omargoher REST URLs are for API calls, not UI

@jesperpedersen

Copy link
Copy Markdown
Contributor

@omargoher Although REST is basically dead - we use HTTP w/ JSON payload instead

@omargoher

omargoher commented May 23, 2026

Copy link
Copy Markdown
Author

@jesperpedersen

@omargoher REST URLs are for API calls, not UI

Good point. I noticed that our backend is still handling some redirects and UI-related navigation. Would it make sense to move those responsibilities to React and keep the backend focused on exposing APIs only?

That way, the frontend can manage the UI flow and control what appears in the URL, while authentication and session handling stay managed through keycloak-js and the Keycloak server.

@jesperpedersen

Copy link
Copy Markdown
Contributor

@omargoher Yes, backend is an API and its data model isn't exposed

@sksingh2005

Copy link
Copy Markdown
Collaborator

Hi @omargoher excellent work man:)
One issue I have found several classes in the backend still handle UI-centric redirects. For example, in
SupportAccessTest.java, I see tests checking for redirects like:

RestAssured.given().redirects().follow(false).get("/support").then().statusCode(303)
    .header("Location", Matchers.endsWith("/support/tickets"));

These @get redirect paths (like /support, /tickets/{id}/edit, etc.) should be removed from the Java code. React Router in the frontend should handle them instead.
I think you already got that ?

quarkus.oidc.application-type=service
quarkus.oidc.authentication.scopes=openid,profile,email
quarkus.oidc.roles.role-claim-path=realm_access/roles
quarkus.oidc.token.principal-claim=sub\

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @omargoher, good catch on the configuration properties, but there is a sneaky syntax issue here I think ?

@sksingh2005

Copy link
Copy Markdown
Collaborator

Hi @omargoher any update ?

@omargoher

Copy link
Copy Markdown
Author

@sksingh2005 Sorry, I'm busy with some work until June 12.

Also, frontend isn't my strongest area. If you want to pick up that part, go ahead. You can use this repo as a reference:
https://github.com/omargoher/quarkus-react-keycloak

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature A new feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants