title: How to make REST Call Logout work with Spring Boot, Vaadin 10 and Keycloak 4?
body: <p>I tried this with Keycloak 4.4.0.Final and 4.6.0.Final. I checked the keycloak server log and I saw the following warning messages in the console output.</p>
  
  <pre><code>10:33:22,882 WARN  [org.keycloak.events] (default task-1) type=REFRESH_TOKEN_ERROR, realmId=master, clientId=security-admin-console, userId=null, ipAddress=127.0.0.1, error=invalid_token, grant_type=refresh_token, client_auth_method=client-secret
  10:40:41,376 WARN  [org.keycloak.events] (default task-5) type=LOGOUT_ERROR, realmId=demo, clientId=eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJqYTBjX18xMHJXZi1KTEpYSGNqNEdSNWViczRmQlpGS3NpSHItbDlud2F3In0.eyJqdGkiOiI1ZTdhYzQ4Zi1mYjkyLTRkZTYtYjcxNC01MTRlMTZiMmJiNDYiLCJleHAiOjE1NDM0MDE2MDksIm5iZiI6MCwiaWF0IjoxNTQzNDAxMzA5LCJpc3MiOiJodHRwOi8vMTI3Lj, userId=null, ipAddress=127.0.0.1, error=invalid_client_credentials
  </code></pre>
  
  <p>So how did build the HTTP request? First, I retrieved the user principal from the HttpSession and cast to the internal Keycloak instance types:</p>
  
  <pre><code>KeycloakAuthenticationToken keycloakAuthenticationToken = (KeycloakAuthenticationToken) request.getUserPrincipal();
  final KeycloakPrincipal keycloakPrincipal = (KeycloakPrincipal)keycloakAuthenticationToken.getPrincipal();
  final RefreshableKeycloakSecurityContext context = (RefreshableKeycloakSecurityContext) keycloakPrincipal.getKeycloakSecurityContext();
  final AccessToken accessToken = context.getToken();
  final IDToken idToken = context.getIdToken();
  </code></pre>
  
  <p>Second, I created the logout URL as in the top stack overflow answer (see  above):</p>
  
  <pre><code>final String logoutURI = idToken.getIssuer() +"/protocol/openid-connect/logout?"+
              "redirect_uri="+response.encodeRedirectURL(url.toString());
  </code></pre>
  
  <p>And now I then build the rest of the HTTP request like so:</p>
  
  <pre><code>KeycloakRestTemplate keycloakRestTemplate = new KeycloakRestTemplate(keycloakClientRequestFactory);
  HttpHeaders headers = new HttpHeaders();
  headers.put("Authorization", Collections.singletonList("Bearer "+idToken.getId()));
  headers.put("Content-Type", Collections.singletonList("application/x-www-form-urlencoded"));
  </code></pre>
  
  <p>And also build the body content string:</p>
  
  <pre><code>StringBuilder bodyContent = new StringBuilder();
  bodyContent.append("client_id=").append(context.getTokenString())
              .append("&amp;")
              .append("client_secret=").append(keycloakCredentialsSecret)
              .append("&amp;")
              .append("user_name=").append(keycloakPrincipal.getName())
              .append("&amp;")
              .append("user_id=").append(idToken.getId())
              .append("&amp;")
              .append("refresh_token=").append(context.getRefreshToken())
              .append("&amp;")
              .append("token=").append(accessToken.getId());
  HttpEntity&lt;String&gt; entity = new HttpEntity&lt;&gt;(bodyContent.toString(), headers);
  //   ...
  ResponseEntity&lt;String&gt; forEntity = keycloakRestTemplate.exchange(logoutURI, HttpMethod.POST, entity, String.class); // *FAILURE*
  </code></pre>
  
  <p>As you can observed, I attempted many variations of theme, but I kept getting invalid user authentication.
  Oh yeah. I injected the keycloak credentials secret from the <code>application.properties</code> into object instance field with @Value</p>
  
  <pre><code>@Value("${keycloak.credentials.secret}")
  private String keycloakCredentialsSecret;
  </code></pre>
  
  <p>Any ideas from Java Spring Security experienced engineers?</p>
  
  <p><em>ADDENDUM</em>
  I created a realm in KC called 'demo' and a client called 'web-portal'
  with the following parameters:</p>
  
  <pre><code>Client Protocol: openid-connect
  Access Type: public
  Standard Flow Enabled: On
  Implicit Flow Enabled: Off
  Direct Access Grants Enabled: On
  Authorization Enabled: Off
  </code></pre>
  
  <p>Here is the code that rebuilds the redirect URI, I forgot to include it here.</p>
  
  <pre><code>final String scheme = request.getScheme();             // http
  final String serverName = request.getServerName();     // hostname.com
  final int serverPort = request.getServerPort();        // 80
  final String contextPath = request.getContextPath();   // /mywebapp
  
  // Reconstruct original requesting URL
  StringBuilder url = new StringBuilder();
  url.append(scheme).append("://").append(serverName);
  
  if (serverPort != 80 &amp;&amp; serverPort != 443) {
      url.append(":").append(serverPort);
  }
  
  url.append(contextPath).append("/offline-page.html");
  </code></pre>
  
  <p>That's all</p>