How to access an authorized uri from inside a SPI

I’m writing an SPI which extends an access token with custom attributes. The reason for this is the limitation to 255 characters in the provided custom attributes. To achieve this i call a REST endpoint of the application which maintains the custom attributes. The application use the keyloak instance where my SPI lives for authorization. I have the restriction that all uri’s in the REST interface of the application have to be authorized.So i call the standard authorization uri of keycloak inside my SPI to obtain an access token. Neither using client credential nor password flow i always get a 401 response when i call the REST endpoint of my application.

I have already read the thread https://keycloak.discourse.group/t/create-accesstoken-inside-custom-spi/248/4, but this didn’t help in my case.

I’m using Keycloak 16.1.1 in a local Docker image for development. I used https://github.com/tholst/keycloak-json-graphql-remote-claim as blueprint for my code.

Additional Note: When i look at the Keycloak log, a javax.resource.RecourceExeption with the text
IJ000453: Unable to get managed connection for java:jboss/datasources/KeycloakDS
occurs when my SPI try to obtain the token.

My code to obtain the token:

private String getAccessToken() throws IOException, InterruptedException {
    String url = "http://localhost:9080/auth/realms/MyRealm/protocol/openid-connect/token";
    Map<String, String> parameters = new HashMap<>();
    parameters.put("grant_type", "client_credentials");
    parameters.put("client_id", "My client id");
    parameters.put("client_secret", "My client secret");
    String form = parameters.keySet().stream()
            .map(key -> key + "=" + URLEncoder.encode(parameters.get(key), StandardCharsets.UTF_8))
            .collect(Collectors.joining("&"));
    HttpClient client = HttpClient.newHttpClient();
    HttpRequest request = HttpRequest.newBuilder().uri(URI.create(url))
            .headers("Content-Type", "application/x-www-form-urlencoded")
            .POST(HttpRequest.BodyPublishers.ofString(form)).build();
    HttpResponse<?> response = client.send(request, HttpResponse.BodyHandlers.ofString());
    String body = response.body().toString();
    var mapper = new ObjectMapper();
    var root = mapper.readTree(body);
    var tokenNode = root.findValue("access_token");
    var token = tokenNode.asText();
    return token;
}

My code to obtain the custom attributes:

public Map<String, Object> getUserAttributes(String userName) {
    var uri = getEnsEndpointUri();
    var timeout = getEnsConnectionTimeout();
    try {
        var accessToken = getAccessToken();
        HttpRequest request = HttpRequest.newBuilder()
                .uri(new URI(uri + userName))
                .setHeader("Authorization", "Bearer " + token)
                .GET()
                .timeout(Duration.ofSeconds(timeout))
                .build();
        HttpClient client = HttpClient.newHttpClient();
        HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
        if (response.statusCode() == HTTP_STATUS_OK) {
            return retrieveToken(response.body());
        }
    } catch (URISyntaxException | IOException | InterruptedException e) {
        e.printStackTrace();
        if (e.getClass().equals(InterruptedException.class)) {
            // Restore interrupted state...
            Thread.currentThread().interrupt();
        }
    }
    return new HashMap<>();
}

Meanwhie i solved my problem by configuring a dedicated client for my SPI.