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>
"http://localhost:8085" needs to be replaced with "http://keycloak-service:8080".
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();