Skip to content

Instantly share code, notes, and snippets.

@slauth
Created October 27, 2021 13:42
Show Gist options
  • Save slauth/19d0a558c386e4679c5b81625a4b2d00 to your computer and use it in GitHub Desktop.
Save slauth/19d0a558c386e4679c5b81625a4b2d00 to your computer and use it in GitHub Desktop.
Helper component that provides a valid token to access Keycloak's REST API
package com.example.demo;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import java.math.BigInteger;
import static java.lang.System.currentTimeMillis;
import static org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED;
public class KeycloakTokenProvider {
private static final long SAFETY_BUFFER_MILLIS = 30_000;
private static final String URL = "http://localhost:8080/auth/realms/master/protocol/openid-connect/token";
private final RestTemplate restTemplate = new RestTemplate();
private SavedKeycloakTokenResponse savedKeycloakTokenResponse;
public synchronized String getToken() {
if (savedKeycloakTokenResponse != null && savedKeycloakTokenResponse.stillValid()) {
return savedKeycloakTokenResponse.keycloakTokenResponse.accessToken;
}
MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
body.add("grant_type", "password");
body.add("client_id", "admin-cli");
body.add("username", "admin");
body.add("password", "admin");
HttpHeaders headers = new HttpHeaders();
headers.setContentType(APPLICATION_FORM_URLENCODED);
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(body, headers);
KeycloakTokenResponse response = restTemplate.postForObject(URL, request, KeycloakTokenResponse.class);
long expiresInMillis = response.getExpiresIn().multiply(BigInteger.valueOf(1_000)).longValueExact();
long validUntil = currentTimeMillis() + expiresInMillis - SAFETY_BUFFER_MILLIS;
savedKeycloakTokenResponse = new SavedKeycloakTokenResponse(response, validUntil);
return response.accessToken;
}
private static class KeycloakTokenResponse {
@JsonProperty("access_token")
private String accessToken;
@JsonProperty("expires_in")
private BigInteger expiresIn;
public String getAccessToken() {
return accessToken;
}
public void setAccessToken(String accessToken) {
this.accessToken = accessToken;
}
public BigInteger getExpiresIn() {
return expiresIn;
}
public void setExpiresIn(BigInteger expiresIn) {
this.expiresIn = expiresIn;
}
}
private static class SavedKeycloakTokenResponse {
private final KeycloakTokenResponse keycloakTokenResponse;
private final long validUntil;
public SavedKeycloakTokenResponse(KeycloakTokenResponse keycloakTokenResponse, long validUntil) {
this.keycloakTokenResponse = keycloakTokenResponse;
this.validUntil = validUntil;
}
boolean stillValid() {
return currentTimeMillis() <= validUntil;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment