Search code examples
javaspring-bootkeycloakresteasykeycloak-admin-client

Keycloak: RESTEASY004655: Unable to invoke request: org.apache.http.conn.HttpHostConnectException:Connection refused


My application has a microservice architecture with eureka and I want to implement oauth2 with keycloak in my auth-service. I have created a Keycloak bean that connects to keycloak and creates realm and client. All services are deployed in docker. But I am getting this error every time I run my application, but keycloak works on localhost:8085 in browser.

org.springframework.beans.factory.BeanCreationException: 
Error creating bean with name 'keycloak' defined in class path resource [backend/authservice/config/KeycloakConfig.class]: 
Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: 
Failed to instantiate [org.keycloak.admin.client.Keycloak]: 
Factory method 'keycloak' threw exception; nested exception is javax.ws.rs.ProcessingException: 
RESTEASY004655: Unable to invoke request: org.apache.http.conn.HttpHostConnectException:
Connect to localhost:8085 [localhost/127.0.0.1] failed: Connection refused

My keycloak config class:

@Configuration
public class KeycloakConfig {
    @Bean
    public Keycloak keycloak() {
        ResteasyClientBuilder resteasyClientBuilder = new ResteasyClientBuilderImpl();

        Keycloak keycloak = KeycloakBuilder.builder()
                .serverUrl("http://localhost:8085")
                .grantType(OAuth2Constants.PASSWORD)
                .realm("master")
                .clientId("admin-cli")
                .username("admin")
                .password("keycloak")
                .resteasyClient(resteasyClientBuilder.connectionPoolSize(10).build())
                .build();

        RealmRepresentation realm = new RealmRepresentation();
        realm.setId("new-relam");
        realm.setRealm("new-relam");
        realm.setEnabled(true);

        keycloak.realms().create(realm);

        ClientRepresentation clientRepresentation = new ClientRepresentation();
        clientRepresentation.setClientId("my-backend");
        clientRepresentation.setRedirectUris(List.of("http://localhost:8081/*"));
        clientRepresentation.setWebOrigins(List.of("http://localhost:8081"));

        keycloak.realm("new-relam").clients().create(clientRepresentation);

        return keycloak;
    }
}

My docker-compose.yml

services:
  eureka-server:
    image: 'eureka-server:1.0'
    container_name: eureka
    ports:
      - "8761:8761"

  auth-server:
    image: 'auth-service:1.0'
    container_name: auth-server
    ports:
      - "8081:8081"
    restart: on-failure
    environment:
      - SPRING_PROFILES_ACTIVE=prod
      - EUREKA_CLIENT_SERVICEURL_DEFAULTZONE=http://eureka-server:8761/eureka
      - SPRING_DATASOURCE_URL=jdbc:postgresql://db:5432/mydb
      - SPRING_DATASOURCE_USERNAME=usr
      - SPRING_DATASOURCE_PASSWORD=password
      - IP_ADDRESS=192.168.115.254
      - TZ=Europe/Kiev
    depends_on:
      - eureka-server
      - db
      - keycloak-service

  db:
    image: 'postgres:latest'
    restart: always
    container_name: db
    environment:
      - POSTGRES_HOST_AUTH_METHOD=trust
      - POSTGRES_USER=usr
      - POSTGRES_PASSWORD=password
      - POSTGRES_DB=mydb

  keycloak-service:
    image: 'keycloak/keycloak:latest'
    container_name: keycloak-service
    ports:
      - "8085:8080"
    restart: always
    environment:
      - KEYCLOAK_ADMIN=admin
      - KEYCLOAK_ADMIN_PASSWORD=keycloak
    command:
      - start-dev

My pom.xml (I use Spring Boot 2.6.0)

   <!-- Swagger -->
        <dependency>
            <groupId>org.springdoc</groupId>
            <artifactId>springdoc-openapi-ui</artifactId>
            <version>1.6.10</version>
        </dependency>
        <!-- Spring Boot -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.7.3</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
            <version>3.0.4</version>
        </dependency>
        <!-- Spring Cloud -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter</artifactId>
            <version>3.1.3</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            <version>3.1.3</version>
            <exclusions>
                <exclusion>
                    <groupId>javax.ws.rs</groupId>
                    <artifactId>jsr311-api</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!-- JWT -->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-oauth2-authorization-server</artifactId>
            <version>0.3.1</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
            <version>3.1.3</version>
        </dependency>
        <!-- Keycloak -->
        <dependency>
            <groupId>org.keycloak</groupId>
            <artifactId>keycloak-admin-client</artifactId>
            <version>21.1.2</version>
        </dependency>
        <!-- Test -->
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <version>5.7.3</version>
            <scope>test</scope>
        </dependency>

Solution:

"http://localhost:8085" needs to be replaced with "http://keycloak-service:8080".


Solution

  • Keycloak server is running inside a Docker container with port mapping from 8085 to 8080. However, when Spring Boot application tries to connect to Keycloak using http://localhost:8085, it's trying to access the Keycloak server running on host machine (outside the Docker network) rather than the container.

    To resolve this issue, I modify Keycloak configuration to connect to the Keycloak server using the appropriate container network name. So "http://localhost:8085" needs to be replaced with "http://keycloak-service:8080".

     Keycloak keycloak = KeycloakBuilder.builder()
                    .serverUrl("http://keycloak-service:8080")
                    .grantType(OAuth2Constants.PASSWORD)
                    .realm("master")
                    .clientId("admin-cli")
                    .username("admin")
                    .password("keycloak")
                    .resteasyClient(resteasyClientBuilder.connectionPoolSize(10).build())
                    .build();