Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Logout user via Keycloak REST API doesn't work

Tags:

keycloak

I have issue while calling Keycloak's logout endpoint from an (mobile) application.

This scenario is supported as stated in its documentation:

/realms/{realm-name}/protocol/openid-connect/logout

The logout endpoint logs out the authenticated user.

The user agent can be redirected to the endpoint, in which case the active user session is logged out. Afterward the user agent is redirected back to the application.

The endpoint can also be invoked directly by the application. To invoke this endpoint directly the refresh token needs to be included as well as the credentials required to authenticate the client.

My request has following format:

POST http://localhost:8080/auth/realms/<my_realm>/protocol/openid-connect/logout Authorization: Bearer <access_token> Content-Type: application/x-www-form-urlencoded  refresh_token=<refresh_token> 

but this error always occurs:

HTTP/1.1 400 Bad Request Connection: keep-alive X-Powered-By: Undertow/1 Server: WildFly/10 Content-Type: application/json Content-Length: 123 Date: Wed, 11 Oct 2017 12:47:08 GMT  {   "error": "unauthorized_client",   "error_description": "UNKNOWN_CLIENT: Client was not identified by any client authenticator" } 

It seems that Keycloak is unable to detect the current client's identity event if I've provided access_token. I've the used same access_token to access other Keycloak's APIs without any problems, like userinfo (/auth/realms//protocol/openid-connect/userinfo).

My request was based on this Keycloak's issue. The author of the issue got it worked but it is not my case.

I'm using Keycloak 3.2.1.Final.

Do you have that same problem? Have you got any idea how to solve it?

like image 741
Manh Ha Avatar asked Oct 11 '17 13:10

Manh Ha


People also ask

How do you implement logout in Keycloak?

enter http://{domain-name}/auth/realms/{realm-name}/protocol/openid-connect/logout?redirect_uri=encodedRedirectUri as Logout Endpoint. Once the user is successfully logged in into Jira/Confluence/Bitbucket/Bamboo, if he tries to logout, the user will get logged out from Keycloak too.

What is backchannel logout in Keycloak?

OpenID Connect Backchannel logout is a mechanism by which Relying Party (RP) applications are logged out with logout requests communicated directly between RPs and OpenID Providers (OP) bypassing the User Agent.

What does Keycloak logout do?

The logout endpoint logs out the authenticated user. The user agent can be redirected to the endpoint, in which case the active user session is logged out. Afterward the user agent is redirected back to the application.


2 Answers

Finally, I've found the solution by looking at the Keycloak's source code: https://github.com/keycloak/keycloak/blob/9cbc335b68718443704854b1e758f8335b06c242/services/src/main/java/org/keycloak/protocol/oidc/endpoints/LogoutEndpoint.java#L169. It says:

If the client is a public client, then you must include a "client_id" form parameter.

So what I was missing is the client_id form parameter. My request should have been:

POST http://localhost:8080/auth/realms/<my_realm>/protocol/openid-connect/logout Authorization: Bearer <access_token> Content-Type: application/x-www-form-urlencoded  client_id=<my_client_id>&refresh_token=<refresh_token> 

The session should be destroyed correctly.

like image 149
Manh Ha Avatar answered Sep 18 '22 18:09

Manh Ha


Works with Keycloak 6.0.

Just for clarity: we do expire refreshToken, but accessToken IS STILL VALID while "Access Token Lifespan" time. Next time user tries to renew access token passing refresh token, Keycloak returns 400 Bad request, what should be catch and send as 401 Unauthorised response.

public void logout(String refreshToken) {     try {         MultiValueMap<String, String> requestParams = new LinkedMultiValueMap<>();         requestParams.add("client_id", "my-client-id");         requestParams.add("client_secret", "my-client-id-secret");         requestParams.add("refresh_token", refreshToken);          logoutUserSession(requestParams);      } catch (Exception e) {         log.info(e.getMessage(), e);         throw e;     } }  private void logoutUserSession(MultiValueMap<String, String> requestParams) {     HttpHeaders headers = new HttpHeaders();     headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);      HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(requestParams, headers);      String url = "/auth/realms/my-realm/protocol/openid-connect/logout";      restTemplate.postForEntity(url, request, Object.class);     // got response 204, no content } 
like image 36
Dmitri Algazin Avatar answered Sep 20 '22 18:09

Dmitri Algazin