You can create a logout service backend that you make available on /logout endpoints of all your services.
When the service is called, it first obtains the ID token for the client used to connect:
curl -k https://<keycloak-host>/auth/realms/<realm>/protocol/openid-connect/token \
-d "grant_type=client_credentials" \
-d "client_id=<client-id>" \
-d "client_secret=<secret>" \
-d "scope=openid"
See this answer.
Then it constructs a redirect URL in a format like this based on host of user:
https://<host>?cache-buster=1445660571
With an optional cache buster.
Create a redirect URL to the authorization server in this format:
https:///auth/realms//protocol/openid-connect/logout?id_token_hint=&post_logout_redirect_uri=<url encoded redirect URL>
Then create a response with status code 303 (See Other) with as Location the URL constructed above, and as headers you set the "kc-access", "kc-state", "OAuth_Token_Request_State" and "request_uri" cookies to expired. Clojure example:
(defn- expired-cookie [host cookie-name]
(str cookie-name "=; "
"domain=." host "; "
"path=/; "
"expires=Thu, 01 Jan 1970 00:00:00 GMT; "
"HttpOnly"))
Example response:
status: 303
headers:
{"Location" "https://<keycloak host>/auth/realms/<realm>/protocol/openid-connect/logout
?id_token_hint=<id token you obtained>
&post_logout_redirect_uri=<url encoded redirect URL>"
"Set-Cookie"
["kc-access=; domain=.https://<domain>; path=/;
expires=Thu, 01 Jan 1970 00:00:00 GMT; HttpOnly"
"kc-state=; domain=.https://<domain>; path=/;
expires=Thu, 01 Jan 1970 00:00:00 GMT; HttpOnly"
"OAuth_Token_Request_State=; domain=.https://<domain>; path=/;
expires=Thu, 01 Jan 1970 00:00:00 GMT; HttpOnly"
"request_uri=; domain=.https://<domain>; path=/;
expires=Thu, 01 Jan 1970 00:00:00 GMT; HttpOnly"]}
This returned response will log the user out and redirect to the constructed redirect URL (for example, where the user came from).
This /logout endpoint can be made available as a route on all services that use Keycloak.