Keycloak OIDC Setup for Local Development
In production, Artemis signs users in through the university's OpenID Connect provider. To work on anything that
touches that flow, you need a provider locally, and this setup gives you one: a Keycloak container that imports a
ready-made artemis-oidc realm with 21 test accounts.
Step 1: Start Keycloak
Keycloak on its own needs no variables, because the compose file pins its version inline:
docker compose -f docker/oidc-test.yml up -d
Together with a database, pass --env-file .env, since those compose files take their image versions from it and
have no fallbacks:
docker compose --env-file .env -f docker/artemis-dev-mysql.yml -f docker/oidc-test.yml up -d
You now have:
| What | Where |
|---|---|
| Keycloak admin console | http://localhost:9080, sign in with admin / admin |
| Realm | artemis-oidc |
| Discovery document | http://localhost:9080/realms/artemis-oidc/.well-known/openid-configuration |
The realm is imported from docker/oidc-test/artemis-oidc-realm.json on every start, so anything you change in the
admin console is gone when you recreate the container. Edit that file instead if you need a change to stick.
Step 2: Point Artemis at it
Copy docker/oidc-test/application-oidc-test.yml into your src/main/resources/config/application-local.yml. That
file holds everything needed: the artemis.user-management.oidc.enabled flag, the claim mappings, and the client and
provider blocks aimed at localhost:9080.
Then start Artemis with the oidc profile:
./gradlew bootRun --args='--spring.profiles.active=dev,artemis,localci,localvc,core,oidc,local'
An alternative that sidesteps the ordering question altogether: application-oidc.yml reads every endpoint from an
environment variable (ARTEMIS_OIDC_ISSUER_URI, ARTEMIS_OIDC_AUTHORIZATION_URI and so on), and environment
variables outrank profile files whatever their order. Setting those is a reasonable option if you switch between the
local and the real provider often.
Step 3: Check the client proxy
If you run the client through the Angular dev server on port 9000, the login redirects have to reach the server
through the proxy. proxy.conf.mjs already forwards them:
context: [
// ...
"/oauth2/",
"/login/oauth2/",
],
target: "http://localhost:8080",
Nothing to do here unless you have changed that file.
Step 4: Sign in
The realm imports one administrator and 20 test users. Every password equals the username, so artemis_test_user_7
signs in with artemis_test_user_7.
| Keycloak account | Keycloak group |
|---|---|
artemis_admin | artemis-admins, artemis-instructors |
artemis_test_user_1 to _5 | artemis-students |
artemis_test_user_6 to _10 | artemis-tutors |
artemis_test_user_11 to _15 | artemis-editors |
artemis_test_user_16 to _20 | artemis-instructors |
Troubleshooting
The browser goes to login.tum.de instead of my container.
The local profile is not last in --spring.profiles.active, so application-oidc.yml and its production defaults
won. Move local to the end, or set the ARTEMIS_OIDC_* environment variables.
Login succeeds, then Artemis fails with Communications link failure.
Keycloak is up but the Artemis database is not. Start the database compose file and try again.
An account signs in but has the wrong role.
Its roles come from the Artemis database, not from Keycloak. Check that the database was migrated with the e2e
Liquibase context, which is what seeds artemis_test_user_1 to _20 and their authorities.
Keycloak is unreachable, or the container sits in Created.
Read the container log with docker logs artemis-keycloak-oidc. A realm import that fails leaves the container in
exactly that state, and the log names the offending part of the JSON.
My admin-console change disappeared.
The realm is re-imported on every container start. Put the change in
docker/oidc-test/artemis-oidc-realm.json and recreate the container.
Related pages
- OIDC Login and Registration: configuring OIDC on a real deployment
- Keycloak SAML2 Setup: the same idea for the SAML2 flow
- User Management: how a first OIDC login provisions an account
- Docker Compose Setup: the local infrastructure this builds on