How to Install Keycloak and Seamlessly Integrate It with Spring Boot and Spring Cloud
This guide walks through downloading, installing, and initializing Keycloak, creating realms, clients, users and roles, then shows step‑by‑step integration with Spring Boot microservices, token propagation via Feign and Zuul, logout handling, email setup, third‑party login, and essential Keycloak terminology.
Installation & Initialization
Download the Keycloak Standalone server distribution from http://www.keycloak.org/downloads.html , unzip it, navigate to KEYCLOAK_PATH/bin and run ./standalone.sh (or ./standalone.sh & for background). After startup, open http://localhost:8080/ to create the initial admin account (e.g., admin/admin).
Administration Console
Log in with the admin credentials to access the console, which provides many menus for managing realms, clients, users, roles, and other settings.
Integration with Spring Boot
Keycloak provides adapters for various frameworks; we use the OpenID Connect Spring Boot adapter. Create a realm, a client (public access type), configure redirect URLs, and define roles ( user-role, test-role). Assign roles to users.
Spring Boot Microservice Example
Assume a microservice ms-content-sample running at http://localhost:8081 with an endpoint /articles protected by the role user-role. Add Keycloak dependencies via BOM and starter, then configure application.yml with the realm, client, and security constraints.
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.keycloak.bom</groupId>
<artifactId>keycloak-adapter-bom</artifactId>
<version>3.4.0.Final</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement> <dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-spring-boot-starter</artifactId>
</dependency> keycloak:
public-client: true
auth-server-url: http://localhost:8080/auth
realm: realm
resource: ms-content-sample
securityConstraints:
- authRoles:
- user-role
securityCollections:
- name: user-role-mappings
patterns:
- /articlesRun the service; accessing /articles as user1 (with user-role) succeeds, while user2 (with test-role) is denied.
Accessing Identity in Controllers
@GetMapping("/articles")
public HashMap<Object, Object> search(Principal principal) {
if (principal instanceof KeycloakPrincipal) {
AccessToken token = ((KeycloakPrincipal) principal).getKeycloakSecurityContext().getToken();
String username = token.getPreferredUsername();
Set<String> roles = token.getRealmAccess().getRoles();
log.info("Current user: {}, roles: {}", username, roles);
}
return null;
}Logout
@RestController
public class LogoutController {
@GetMapping("/logout")
public String logout(HttpServletRequest request) throws ServletException {
request.logout();
return "Logout successful";
}
}Integration with Spring Cloud
For distributed applications, propagate the Keycloak token between services using Feign interceptors or Zuul filters.
Feign Token Propagation
public class KeycloakRequestInterceptor implements RequestInterceptor {
private static final String AUTHORIZATION_HEADER = "Authorization";
@Override
public void apply(RequestTemplate template) {
ServletRequestAttributes attrs = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
Principal principal = attrs.getRequest().getUserPrincipal();
if (principal instanceof KeycloakPrincipal) {
KeycloakSecurityContext ctx = ((KeycloakPrincipal) principal).getKeycloakSecurityContext();
if (ctx instanceof RefreshableKeycloakSecurityContext) {
((RefreshableKeycloakSecurityContext) ctx).refreshExpiredToken(true);
template.header(AUTHORIZATION_HEADER, "Bearer " + ctx.getTokenString());
}
}
}
}Zuul Token Propagation
@Component
public class KeycloakRouteZuulFilter extends ZuulFilter {
private static final String AUTHORIZATION_HEADER = "Authorization";
@Override
public String filterType() { return FilterConstants.ROUTE_TYPE; }
@Override
public int filterOrder() { return 1; }
@Override
public boolean shouldFilter() {
RequestContext ctx = RequestContext.getCurrentContext();
Principal p = ctx.getRequest().getUserPrincipal();
return p != null && p instanceof KeycloakPrincipal;
}
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
if (ctx.getRequest().getHeader(AUTHORIZATION_HEADER) == null) {
addKeycloakTokenToHeader(ctx);
}
return null;
}
private void addKeycloakTokenToHeader(RequestContext ctx) {
Principal p = ctx.getRequest().getUserPrincipal();
KeycloakSecurityContext sec = ((KeycloakPrincipal) p).getKeycloakSecurityContext();
if (sec instanceof RefreshableKeycloakSecurityContext) {
ctx.addZuulRequestHeader(AUTHORIZATION_HEADER,
"Bearer " + ((RefreshableKeycloakSecurityContext) sec).getTokenString());
}
}
}Configure non‑Zuul clients as bearer-only so they rely on token forwarding from the gateway.
Login Configuration and Third‑Party Identity Providers
Enable user registration, “Remember Me”, and add external identity providers such as GitHub by creating a GitHub OAuth application, obtaining the client ID and secret, and filling them in the Keycloak admin console.
Keycloak Terminology
Definitions of Resource Server, Resource, Scope, Permission, Policy, Policy Provider, and Permission Ticket are provided to understand the underlying authorization model.
Programmer DD
A tinkering programmer and author of "Spring Cloud Microservices in Action"
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
