Umfassender Leitfaden fΓΌr Authentifizierung und Autorisierung
Identity and Access Management (IAM) umfasst:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β JavaFX Frontend β
β (de.ruu.app.jeeeraaah.frontend.ui.fx) β
ββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββ
β HTTP + JWT Bearer Token
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Open Liberty Server (Backend) β
β (de.ruu.app.jeeeraaah.backend.api.ws.rs) β
β βββββββββββββββββββββββββββββββββββββββββββββββββ β
β β MicroProfile JWT (mpJwt-2.1) β β
β β - JWT Token Validierung β β
β β - Signatur-PrΓΌfung via JWKS β β
β β - Rollen-Extraktion aus "groups" Claim β β
β βββββββββββββββββββββββββββββββββββββββββββββββββ β
ββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββ
β JWKS (Public Keys)
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Keycloak Server β
β βββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Realm: jeeeraaah-realm β β
β β - User Management β β
β β - Roles & Groups β β
β β - OAuth2 / OpenID Connect β β
β β - JWT Token Issuer β β
β βββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Frontend Keycloak Backend
β β β
β 1. Login Request β β
β ββββββββββββββββββββββ>β β
β (username/password) β β
β β β
β 2. JWT Access Token β β
β <βββββββββββββββββββββββ β
β β β
β 3. API Request β β
β + Bearer Token β β
β ββββββββββββββββββββββββββββββββββββββββββββββ> β
β β β
β β 4. Token Validation β
β β <βββββββββββββββββββββββ
β β (JWKS Public Keys) β
β β β
β β 5. Signature OK β
β β ββββββββββββββββββββββ>β
β β β
β β 6. Extract Roles β
β β from "groups" claim β
β β β
β 7. API Response β β
β <ββββββββββββββββββββββββββββββββββββββββββββββββ
β β β
Ein Realm ist eine isolierte DomΓ€ne fΓΌr Benutzer und Anwendungen.
// Automatische Realm-Erstellung via KeycloakRealmSetup.java
RealmRepresentation realm = new RealmRepresentation();
realm.setRealm("jeeeraaah-realm");
realm.setEnabled(true);
realm.setDisplayName("Jeeeraaah Task Management");
realm.setLoginTheme("keycloak");
keycloak.realms().create(realm);
Manuelle Erstellung in der Admin Console:
jeeeraaah-realmEin Client reprΓ€sentiert die Frontend-Anwendung.
// Automatische Client-Erstellung
ClientRepresentation client = new ClientRepresentation();
client.setClientId("jeeeraaah-frontend");
client.setName("Jeeeraaah Frontend");
client.setEnabled(true);
client.setPublicClient(true); // Kein Client Secret (Public Client)
client.setDirectAccessGrantsEnabled(true); // Resource Owner Password Flow
client.setStandardFlowEnabled(true); // Authorization Code Flow
client.setServiceAccountsEnabled(false);
// Redirect URIs
client.setRedirectUris(Arrays.asList(
"http://localhost:*",
"https://localhost:*"
));
// Web Origins (CORS)
client.setWebOrigins(Arrays.asList("*"));
Manuelle Konfiguration:
jeeeraaah-realmOpenID Connectjeeeraaah-frontendOff (Public Client)Offhttp://localhost:*http://localhost:**Protocol Mappers fΓΌgen zusΓ€tzliche Claims (Daten) zum JWT Token hinzu.
Open Liberty erwartet Rollen im Top-Level βgroupsβ Claim, nicht verschachtelt in realm_access.roles.
// Automatische Mapper-Erstellung
ProtocolMapperRepresentation mapper = new ProtocolMapperRepresentation();
mapper.setName("groups-claim-mapper");
mapper.setProtocol("openid-connect");
mapper.setProtocolMapper("oidc-usermodel-realm-role-mapper");
Map<String, String> config = new HashMap<>();
config.put("claim.name", "groups"); // Liberty erwartet "groups"
config.put("jsonType.label", "String");
config.put("multivalued", "true"); // Array von Rollen
config.put("id.token.claim", "true"); // In ID Token
config.put("access.token.claim", "true"); // In Access Token
config.put("userinfo.token.claim", "true"); // In UserInfo Endpoint
mapper.setConfig(config);
Manuelle Konfiguration:
jeeeraaah-frontend β βClient scopesβ β βjeeeraaah-frontend-dedicatedβUser Realm Rolegroups-claim-mappergroupsStringVorher (Keycloak Standard):
{
"realm_access": {
"roles": ["admin", "user"]
}
}
Nachher (Liberty-kompatibel):
{
"groups": ["admin", "user"]
}
FΓΌgt die Audience jeeeraaah-backend zum Token hinzu.
ProtocolMapperRepresentation audienceMapper = new ProtocolMapperRepresentation();
audienceMapper.setName("audience-mapper");
audienceMapper.setProtocol("openid-connect");
audienceMapper.setProtocolMapper("oidc-audience-mapper");
Map<String, String> config = new HashMap<>();
config.put("included.custom.audience", "jeeeraaah-backend");
config.put("access.token.claim", "true");
config.put("id.token.claim", "false");
audienceMapper.setConfig(config);
Manuelle Konfiguration:
jeeeraaah-frontend β βClient scopesβ β βjeeeraaah-frontend-dedicatedβaudience-mapperjeeeraaah-backendRealm Roles definieren die Berechtigungen.
// Automatisch
RoleRepresentation adminRole = new RoleRepresentation();
adminRole.setName("admin");
adminRole.setDescription("Administrator role with full access");
RoleRepresentation userRole = new RoleRepresentation();
userRole.setName("user");
userRole.setDescription("Regular user role with limited access");
keycloak.realm("jeeeraaah-realm").roles().create(adminRole);
keycloak.realm("jeeeraaah-realm").roles().create(userRole);
Manuelle Erstellung:
jeeeraaah-realm β βRealm rolesβadminAdministrator role with full accessuserRegular user role with limited access// Automatisch
UserRepresentation user = new UserRepresentation();
user.setUsername("testuser");
user.setEmail("testuser@example.com");
user.setFirstName("Test");
user.setLastName("User");
user.setEnabled(true);
user.setEmailVerified(true);
// Benutzer erstellen
Response response = keycloak.realm("jeeeraaah-realm")
.users().create(user);
String userId = CreatedResponseUtil.getCreatedId(response);
// Passwort setzen
CredentialRepresentation credential = new CredentialRepresentation();
credential.setType(CredentialRepresentation.PASSWORD);
credential.setValue("password123");
credential.setTemporary(false);
keycloak.realm("jeeeraaah-realm")
.users().get(userId)
.resetPassword(credential);
// Rollen zuweisen
RoleRepresentation adminRole = keycloak.realm("jeeeraaah-realm")
.roles().get("admin").toRepresentation();
keycloak.realm("jeeeraaah-realm")
.users().get(userId)
.roles().realmLevel()
.add(Arrays.asList(adminRole));
Manuelle Erstellung:
jeeeraaah-realm β βUsersβtestusertestuser@example.comTestUserpassword123admin und/oder userDas Projekt enthΓ€lt eine automatische Setup-Klasse:
# Docker-Container laufen lassen
docker-compose up -d
# Setup ausfΓΌhren (im Projekt)
cd root/lib/keycloak_admin
mvn exec:java -Dexec.mainClass="de.ruu.lib.keycloak.admin.setup.KeycloakRealmSetup"
Was macht KeycloakRealmSetup.java?
jeeeraaah-realm erstellen (falls nicht vorhanden)jeeeraaah-frontend konfigurierenadmin und user erstellenAusgabe:
β
Realm 'jeeeraaah-realm' ist bereit
β
Client 'jeeeraaah-frontend' konfiguriert
β
'groups' Claim Mapper erfolgreich erstellt
β Rollen werden nun als Top-Level 'groups' Claim ins Token geschrieben
β Liberty Server kann Rollen jetzt lesen!
β
Audience Mapper erstellt
β
Rolle 'admin' erstellt
β
Rolle 'user' erstellt
β
Benutzer 'testuser' erstellt
β
Rolle 'admin' zu Benutzer 'testuser' zugewiesen
In server.xml mΓΌssen folgende Features aktiviert sein:
<featureManager>
<!-- Jakarta EE 10.0 + MicroProfile 6.1 -->
<feature>jakartaee-10.0</feature>
<feature>microProfile-6.1</feature>
<!-- MicroProfile JWT fΓΌr Token-Validierung -->
<feature>mpJwt-2.1</feature>
<!-- Application Security fΓΌr @RolesAllowed -->
<feature>appSecurity-5.0</feature>
</featureManager>
<mpJwt id="jwtConsumer"
jwksUri="http://localhost:8080/realms/jeeeraaah-realm/protocol/openid-connect/certs"
issuer="http://localhost:8080/realms/jeeeraaah-realm"
userNameAttribute="preferred_username"
groupNameAttribute="groups">
<!-- OPTIONAL: Audience Validierung (fΓΌr Production) -->
<!-- audiences="jeeeraaah-backend" -->
</mpJwt>
| Attribut | Beschreibung | Beispiel |
|---|---|---|
jwksUri |
URL zu Keycloaks Public Keys (JWKS = JSON Web Key Set) Liberty lΓ€dt diese Keys und prΓΌft die Token-Signatur |
http://localhost:8080/realms/jeeeraaah-realm/protocol/openid-connect/certs |
issuer |
Erwarteter Token-Aussteller (Issuer Claim iss)Muss exakt mit Keycloak Realm URL ΓΌbereinstimmen |
http://localhost:8080/realms/jeeeraaah-realm |
userNameAttribute |
JWT Claim fΓΌr den Benutzernamen Liberty extrahiert diesen Wert als Principal |
preferred_username |
groupNameAttribute |
JWT Claim fΓΌr Rollen/Gruppen β οΈ WICHTIG: Muss auf groups gesetzt sein! |
groups |
audiences |
Erwartete Audience (Optional) FΓΌr Production-Sicherheit aktivieren |
jeeeraaah-backend |
| URL | Beschreibung |
|---|---|
http://localhost:8080/realms/jeeeraaah-realm/.well-known/openid-configuration |
OpenID Connect Discovery (Metadaten) |
http://localhost:8080/realms/jeeeraaah-realm/protocol/openid-connect/certs |
JWKS Public Keys (Token-Signatur-Validierung) |
http://localhost:8080/realms/jeeeraaah-realm/protocol/openid-connect/token |
Token Endpoint (Login) |
import jakarta.annotation.security.RolesAllowed;
import jakarta.annotation.security.PermitAll;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.SecurityContext;
@Path("/taskgroup")
public class TaskGroupResource
{
/**
* Γffentlicher Endpoint - kein Login erforderlich
*/
@GET
@Path("/public")
@Produces(MediaType.APPLICATION_JSON)
@PermitAll
public Response getPublicData()
{
return Response.ok("Public data").build();
}
/**
* GeschΓΌtzter Endpoint - nur fΓΌr angemeldete Benutzer
* (unabhΓ€ngig von der Rolle)
*/
@GET
@Path("/protected")
@Produces(MediaType.APPLICATION_JSON)
@RolesAllowed({"user", "admin"})
public Response getProtectedData(@Context SecurityContext securityContext)
{
String username = securityContext.getUserPrincipal().getName();
return Response.ok("Hello " + username).build();
}
/**
* Admin-Endpoint - nur fΓΌr Admin-Rolle
*/
@GET
@Path("/admin")
@Produces(MediaType.APPLICATION_JSON)
@RolesAllowed("admin")
public Response getAdminData(@Context SecurityContext securityContext)
{
String username = securityContext.getUserPrincipal().getName();
boolean isAdmin = securityContext.isUserInRole("admin");
return Response.ok("Admin access granted for " + username).build();
}
}
| Annotation | Beschreibung |
|---|---|
@PermitAll |
Jeder darf zugreifen (kein Token erforderlich) |
@DenyAll |
Niemand darf zugreifen |
@RolesAllowed("admin") |
Nur Benutzer mit Rolle admin |
@RolesAllowed({"user", "admin"}) |
Benutzer mit Rolle user ODER admin |
@Context
private SecurityContext securityContext;
public void someMethod()
{
// Benutzername abrufen
String username = securityContext.getUserPrincipal().getName();
// Rolle prΓΌfen
boolean isAdmin = securityContext.isUserInRole("admin");
boolean isUser = securityContext.isUserInRole("user");
// JWT Token im Request Header verfΓΌgbar via:
// @HeaderParam("Authorization") String authHeader
}
@Singleton
@Slf4j
public class KeycloakAuthService
{
private String keycloakServerUrl;
private String realm;
private String clientId;
private String tokenUrl;
@Getter private String accessToken;
@Getter private String refreshToken;
@PostConstruct
private void init()
{
// Konfiguration aus microprofile-config.properties
keycloakServerUrl = ConfigProvider.getConfig()
.getOptionalValue("keycloak.auth.server.url", String.class)
.orElse("http://localhost:8080");
realm = ConfigProvider.getConfig()
.getOptionalValue("keycloak.realm", String.class)
.orElse("jeeeraaah-realm");
clientId = ConfigProvider.getConfig()
.getOptionalValue("keycloak.client-id", String.class)
.orElse("jeeeraaah-frontend");
tokenUrl = String.format("%s/realms/%s/protocol/openid-connect/token",
keycloakServerUrl, realm);
}
/**
* Benutzer-Login mit Resource Owner Password Grant
*/
public String login(String username, String password)
throws IOException, InterruptedException
{
String formData = String.format(
"grant_type=password&client_id=%s&username=%s&password=%s",
URLEncoder.encode(clientId, StandardCharsets.UTF_8),
URLEncoder.encode(username, StandardCharsets.UTF_8),
URLEncoder.encode(password, StandardCharsets.UTF_8)
);
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(tokenUrl))
.header("Content-Type", "application/x-www-form-urlencoded")
.POST(HttpRequest.BodyPublishers.ofString(formData))
.build();
HttpClient client = HttpClient.newHttpClient();
HttpResponse<String> response = client.send(request,
HttpResponse.BodyHandlers.ofString());
if (response.statusCode() == 200)
{
JsonNode json = new ObjectMapper().readTree(response.body());
accessToken = json.get("access_token").asText();
refreshToken = json.get("refresh_token").asText();
log.info("Login erfolgreich fΓΌr Benutzer: {}", username);
return accessToken;
}
else
{
log.error("Login fehlgeschlagen: {}", response.body());
throw new IOException("Login failed: " + response.statusCode());
}
}
}
@ApplicationScoped
public class TaskGroupServiceClient
{
@Inject
private KeycloakAuthService authService;
private final Client client = ClientBuilder.newClient();
public TaskGroupDTO getTaskGroup(Long id)
{
String token = authService.getAccessToken();
Response response = client
.target("http://localhost:9080/taskgroup/{id}")
.resolveTemplate("id", id)
.request(MediaType.APPLICATION_JSON)
.header("Authorization", "Bearer " + token) // β JWT Token!
.get();
if (response.getStatus() == 200)
{
return response.readEntity(TaskGroupDTO.class);
}
else if (response.getStatus() == 401)
{
throw new RuntimeException("Unauthorized - Token ungΓΌltig");
}
else if (response.getStatus() == 403)
{
throw new RuntimeException("Forbidden - Keine Berechtigung");
}
else
{
throw new RuntimeException("API Error: " + response.getStatus());
}
}
}
Automatisch den JWT Token zu allen Requests hinzufΓΌgen:
@Provider
public class AuthorizationHeaderFilter implements ClientRequestFilter
{
@Inject
private KeycloakAuthService authService;
@Override
public void filter(ClientRequestContext requestContext)
{
String token = authService.getAccessToken();
if (token != null && !token.isEmpty())
{
requestContext.getHeaders()
.putSingle("Authorization", "Bearer " + token);
}
}
}
// Filter registrieren
Client client = ClientBuilder.newClient()
.register(AuthorizationHeaderFilter.class);
cd /home/r-uu/develop/github/main
docker-compose up -d
# Status prΓΌfen
docker ps | grep -E "keycloak|postgres"
Erwartete Ausgabe:
keycloak Up 2 minutes (healthy)
postgres Up 2 minutes (healthy)
cd root/lib/keycloak_admin
mvn exec:java -Dexec.mainClass="de.ruu.lib.keycloak.admin.setup.KeycloakRealmSetup"
Erwartete Ausgabe:
β
Realm 'jeeeraaah-realm' ist bereit
β
Client 'jeeeraaah-frontend' konfiguriert
β
'groups' Claim Mapper erfolgreich erstellt
β
Audience Mapper erstellt
β
Rollen erstellt: admin, user
β
Testbenutzer 'testuser' erstellt
URL: http://localhost:8080/admin
Login:
adminadminPrΓΌfen:
jeeeraaah-realm existiertjeeeraaah-frontend existierttestuser existiert mit Rolle adminjeeeraaah-frontend-dedicated β Mappers:
groups-claim-mapperaudience-mappercd root/app/jeeeraaah/backend/api/ws_rs
# Mit Maven
mvn liberty:dev
# Oder direkt
mvn liberty:run
Erwartete Ausgabe:
[AUDIT ] CWWKZ0001I: Application jeeeraaah started in 5.123 seconds.
[AUDIT ] CWWKF0012I: The server installed the following features:
[jakartaee-10.0, mpJwt-2.1, appSecurity-5.0, ...]
Server lΓ€uft auf: http://localhost:9080
cd root/app/jeeeraaah/frontend/ui/fx
# App starten
mvn javafx:run
# Oder den AppRunner
java -jar target/r-uu.app.jeeeraaah.frontend.ui.fx-0.0.1.jar
testuserpassword123Erwartetes Ergebnis:
β
Login erfolgreich
β
Access Token erhalten
β
Dashboard wird angezeigt
# 1. Token abrufen
TOKEN=$(curl -s -X POST \
"http://localhost:8080/realms/jeeeraaah-realm/protocol/openid-connect/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=password" \
-d "client_id=jeeeraaah-frontend" \
-d "username=testuser" \
-d "password=password123" \
| jq -r '.access_token')
# 2. API-Aufruf mit Token
curl -X GET \
"http://localhost:9080/taskgroup/allFlat" \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: application/json"
Erwartete Antwort:
[
{
"id": 1,
"name": "Feature Set 1",
"description": "Backend Development"
}
]
Symptom:
HTTP 401 Unauthorized
MΓΆgliche Ursachen:
# Token dekodieren (mit jwt.io oder jq)
echo $TOKEN | cut -d'.' -f2 | base64 -d | jq
PrΓΌfen:
exp (Expiration): Token noch gΓΌltig?iss (Issuer): Stimmt mit Liberty issuer ΓΌberein?groups: EnthΓ€lt die erforderlichen Rollen?LΓΆsung:
# Neuen Token abrufen
TOKEN=$(curl -s -X POST ...)
Liberty Logs prΓΌfen:
tail -f wlp/usr/servers/defaultServer/logs/messages.log
Fehler:
CWWKS6031E: The JSON Web Token (JWT) consumer cannot contact the URL
[http://localhost:8080/realms/jeeeraaah-realm/protocol/openid-connect/certs]
LΓΆsung:
docker ps | grep keycloakcurl http://localhost:8080/realms/jeeeraaah-realm/protocol/openid-connect/certsLiberty Logs:
CWWKS6022E: The issuer [http://localhost:8080/realms/jeeeraaah-realm]
specified in the token does not match the issuer attribute
LΓΆsung:
server.xml prΓΌfen:
<mpJwt issuer="http://localhost:8080/realms/jeeeraaah-realm" />
Symptom:
HTTP 403 Forbidden
Ursache: Token ist gΓΌltig, aber Benutzer hat nicht die erforderliche Rolle.
Diagnose:
# Token dekodieren
echo $TOKEN | cut -d'.' -f2 | base64 -d | jq '.groups'
Erwartete Ausgabe:
["admin", "user"]
Wenn groups fehlt:
β Groups Claim Mapper fehlt!
LΓΆsung:
jeeeraaah-frontend β Client scopes β jeeeraaah-frontend-dedicatedgroups-claim-mapper muss existierenSymptom:
{
"realm_access": {
"roles": ["admin"]
}
}
Aber Liberty erwartet:
{
"groups": ["admin"]
}
Ursache: Groups Claim Mapper fehlt oder falsch konfiguriert.
LΓΆsung:
// KeycloakRealmSetup erneut ausfΓΌhren
mvn exec:java -Dexec.mainClass="de.ruu.lib.keycloak.admin.setup.KeycloakRealmSetup"
Oder manuell:
jeeeraaah-frontend β Client scopes β jeeeraaah-frontend-dedicatedgroups-claim-mappergroups β WICHTIG!StringSymptom:
docker ps | grep keycloak
# Kein Output oder Status: unhealthy
Diagnose:
docker logs keycloak
MΓΆgliche Ursachen:
Fehler:
Caused by: org.postgresql.util.PSQLException: Connection refused
LΓΆsung:
# PostgreSQL-Status prΓΌfen
docker ps | grep postgres
# Falls nicht healthy: Neustarten
docker-compose restart postgres
# Warten bis healthy, dann Keycloak starten
docker-compose up -d keycloak
Fehler:
Error starting userland proxy: listen tcp4 0.0.0.0:8080: bind: address already in use
LΓΆsung:
# Port 8080 freimachen oder in docker-compose.yml Γ€ndern
lsof -i :8080
kill <PID>
Symptom:
SecurityContext.isUserInRole("admin") liefert falseDiagnose:
Liberty server.xml prΓΌfen:
<mpJwt groupNameAttribute="groups" />
NICHT:
<mpJwt groupNameAttribute="realm_access.roles" />
Token prΓΌfen:
echo $TOKEN | cut -d'.' -f2 | base64 -d | jq '.groups'
Erwartete Ausgabe:
["admin", "user"]
Wenn null: β Groups Claim Mapper fehlt (siehe Problem 3)
Development:
<mpJwt id="jwtConsumer"
jwksUri="..."
issuer="..."
userNameAttribute="preferred_username"
groupNameAttribute="groups">
<!-- audiences deaktiviert -->
</mpJwt>
Production:
<mpJwt id="jwtConsumer"
jwksUri="..."
issuer="..."
audiences="jeeeraaah-backend" β Aktivieren!
userNameAttribute="preferred_username"
groupNameAttribute="groups" />
Production:
<!-- Keycloak -->
https://auth.example.com/realms/jeeeraaah-realm/...
<!-- Liberty -->
<httpEndpoint httpsPort="9443" httpPort="-1" />
FΓΌr Backend-zu-Backend Kommunikation:
// Keycloak Client-Konfiguration
client.setPublicClient(false); // Vertraulicher Client
client.setClientAuthenticatorType("client-secret");
// Token-Anfrage mit Client Secret
curl -X POST "http://localhost:8080/realms/jeeeraaah-realm/protocol/openid-connect/token" \
-d "grant_type=client_credentials" \
-d "client_id=jeeeraaah-backend-service" \
-d "client_secret=YOUR_SECRET_HERE"
Keycloak Admin Console:
jeeeraaah-realm β Realm settings β Tokenspublic String refreshAccessToken() throws IOException, InterruptedException
{
String formData = String.format(
"grant_type=refresh_token&client_id=%s&refresh_token=%s",
URLEncoder.encode(clientId, StandardCharsets.UTF_8),
URLEncoder.encode(refreshToken, StandardCharsets.UTF_8)
);
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(tokenUrl))
.header("Content-Type", "application/x-www-form-urlencoded")
.POST(HttpRequest.BodyPublishers.ofString(formData))
.build();
HttpClient client = HttpClient.newHttpClient();
HttpResponse<String> response = client.send(request,
HttpResponse.BodyHandlers.ofString());
if (response.statusCode() == 200)
{
JsonNode json = new ObjectMapper().readTree(response.body());
accessToken = json.get("access_token").asText();
refreshToken = json.get("refresh_token").asText();
return accessToken;
}
else
{
throw new IOException("Token refresh failed");
}
}
Liberty cached die Public Keys automatisch. Konfigurierbar via:
<mpJwt jwksCacheLifetimeMs="600000" /> <!-- 10 Minuten -->
// Jersey Client mit Connection Pooling
ClientConfig config = new ClientConfig();
config.property(ClientProperties.CONNECT_TIMEOUT, 5000);
config.property(ClientProperties.READ_TIMEOUT, 30000);
Client client = ClientBuilder.newClient(config);
tail -f wlp/usr/servers/defaultServer/logs/messages.log | grep -E "CWWKS|JWT"
Admin Console:
jeeeraaah-realm β Eventsjboss-loggingEvents anzeigen:
| Komponente | Konfiguration | Wert |
|---|---|---|
| Keycloak | Realm | jeeeraaah-realm |
| Β | Client ID | jeeeraaah-frontend |
| Β | Client Type | Public Client |
| Β | Groups Claim Mapper | Claim Name: groups β KRITISCH! |
| Β | Token Endpoint | http://localhost:8080/realms/jeeeraaah-realm/protocol/openid-connect/token |
| Liberty | Feature | mpJwt-2.1, appSecurity-5.0 |
| Β | JWKS URI | http://localhost:8080/realms/jeeeraaah-realm/protocol/openid-connect/certs |
| Β | Issuer | http://localhost:8080/realms/jeeeraaah-realm |
| Β | groupNameAttribute | groups β KRITISCH! |
| Frontend | Auth Service | KeycloakAuthService.java |
| Β | Token Header | Authorization: Bearer <token> |
docker ps)jeeeraaah-realm existiertjeeeraaah-frontend konfiguriertclaim.name=groupsadmin und user existierenserver.xml konfiguriert:
mpJwt Feature aktiviertjwksUri korrektissuer korrektgroupNameAttribute="groups" gesetzt@RolesAllowed gesichertErstellt: 2026-02-16
Autor: GitHub Copilot
Version: 1.0
Status: β
Produktionsreif