I'm trying to programatically create a Keycloak realm, with associated client on Keycloak 24.0.0
using the library: org.keycloak:keycloak-admin-client:24.0.0
.
I want to turn on Client authentication
and Authorization
for the client.
I'm creating a client, and then subsequently updating it to have authorizationServicesEnabled(true);
like so:
ClientRepresentation clientRepresentation = getClientRepresentation(realm);
ClientResource clientResource = getClientResource(realm, clientRepresentation);
clientRepresentation.setAuthorizationServicesEnabled(true);
clientRepresentation.setStandardFlowEnabled(true);
clientRepresentation.setDirectAccessGrantsEnabled(true);
clientRepresentation.setPublicClient(true);
clientRepresentation.setEnabled(true);
clientRepresentation.setServiceAccountsEnabled(true);
clientRepresentation.setAlwaysDisplayInConsole(true);
clientRepresentation.setAttributes(Map.of(
"oauth2.device.authorization.grant.enabled", "false",
"oidc.ciba.grant.enabled", "false",
"login_theme", "base",
"display.on.consent.screen", "false",
"backchannel.logout.url", "",
"backchannel.logout.session.required", "true",
"backchannel.logout.revoke.offline.tokens", "false"
));
clientRepresentation.setRedirectUris(List.of(publicUrl + "/*"));
clientResource.update(clientRepresentation);
Here is the PUT body that was sent when I stepped through the process in debug:
{
"id": "de890c6a-7695-4cce-b512-87989059860c",
"clientId": "my-client",
"name": "my-client",
"description": null,
"rootUrl": null,
"adminUrl": null,
"baseUrl": null,
"surrogateAuthRequired": false,
"enabled": true,
"alwaysDisplayInConsole": true,
"clientAuthenticatorType": "client-secret",
"secret": null,
"registrationAccessToken": null,
"defaultRoles": null,
"redirectUris": [
"http://localhost:8080/*"
],
"webOrigins": [],
"notBefore": 0,
"bearerOnly": false,
"consentRequired": false,
"standardFlowEnabled": true,
"implicitFlowEnabled": false,
"directAccessGrantsEnabled": true,
"serviceAccountsEnabled": true,
"authorizationServicesEnabled": true,
"directGrantsOnly": null,
"publicClient": true,
"frontchannelLogout": false,
"protocol": "openid-connect",
"attributes": {
"oidc.ciba.grant.enabled": "false",
"client.secret.creation.time": "1709725705",
"backchannel.logout.session.required": "true",
"login_theme": "base",
"display.on.consent.screen": "false",
"oauth2.device.authorization.grant.enabled": "false",
"backchannel.logout.revoke.offline.tokens": "false"
},
"authenticationFlowBindingOverrides": {},
"fullScopeAllowed": true,
"nodeReRegistrationTimeout": -1,
"registeredNodes": null,
"protocolMappers": [
{
"id": "a939828f-f524-4d06-aacf-490ea0e2e105",
"name": "Client IP Address",
"protocol": "openid-connect",
"protocolMapper": "oidc-usersessionmodel-note-mapper",
"consentRequired": false,
"consentText": null,
"config": {
"user.session.note": "clientAddress",
"introspection.token.claim": "true",
"id.token.claim": "true",
"access.token.claim": "true",
"claim.name": "clientAddress",
"jsonType.label": "String"
}
},
{
"id": "b62609d1-330f-445e-ab73-edf78b16f396",
"name": "Client ID",
"protocol": "openid-connect",
"protocolMapper": "oidc-usersessionmodel-note-mapper",
"consentRequired": false,
"consentText": null,
"config": {
"user.session.note": "client_id",
"introspection.token.claim": "true",
"id.token.claim": "true",
"access.token.claim": "true",
"claim.name": "client_id",
"jsonType.label": "String"
}
},
{
"id": "1d78e050-38eb-4da5-950e-fe5112471ddf",
"name": "Client Host",
"protocol": "openid-connect",
"protocolMapper": "oidc-usersessionmodel-note-mapper",
"consentRequired": false,
"consentText": null,
"config": {
"user.session.note": "clientHost",
"introspection.token.claim": "true",
"id.token.claim": "true",
"access.token.claim": "true",
"claim.name": "clientHost",
"jsonType.label": "String"
}
}
],
"clientTemplate": null,
"useTemplateConfig": null,
"useTemplateScope": null,
"useTemplateMappers": null,
"defaultClientScopes": [
"web-origins",
"acr",
"roles",
"profile",
"email"
],
"optionalClientScopes": [
"address",
"phone",
"offline_access",
"microprofile-jwt"
],
"authorizationSettings": null,
"access": {
"view": true,
"configure": true,
"manage": true
},
"origin": null
}
I can see that "authorizationServicesEnabled": true
is there, but in the Admin console, it's still not switched on under the Capability Config part of the Client Settings tab:
When you turn on those two switches in the Keycloak admin console, it shows a Credentials tab with a Client Id and Secret
Client Authenticator, and a Client secret. I think I need to create these programatically and associate them with the ClientRepresentation
, but I'm not convinced, as I created a client in the Admin console with the same settings and examined the request payload going to the api and it was the same as above.
So my question is:
How do I replicate what happens when you turn these two switches on in the UI programatically?
Any/all help appreciated.
After examining the Admin Console UI code I could see that the client needs to not be a public client for it to work as expected.
Removing the line:
clientRepresentation.setPublicClient(true);
made it all work as expected.