Framework Adapters
The general pattern
Section titled “The general pattern”Every framework integration follows the same two-role model:
- Frontend / OIDC client: any library that implements the Authorization Code + PKCE flow (keycloak-js for browsers, AppAuth for mobile, MSAL for Microsoft stacks, etc.).
- Backend / resource server: any library that validates Bearer JWTs against the realm’s JWKS endpoint.
The key insight is that the backend does not need a Keycloak-specific library. It only needs a library that can validate a JWT against a JWKS URL — which is a standard feature of every mature OAuth2/OIDC ecosystem.
Spring Boot (Spring Security OAuth2 Resource Server)
Section titled “Spring Boot (Spring Security OAuth2 Resource Server)”Add the Spring Security OAuth2 Resource Server dependency to your pom.xml:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-oauth2-resource-server</artifactId></dependency>Then point Spring at your realm’s issuer URI. Spring automatically fetches the JWKS, verifies incoming JWTs, and populates SecurityContextHolder with the decoded claims:
spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: http://localhost:8080/realms/my-appSpring Security derives the JWKS URL automatically from the issuer URI by appending /protocol/openid-connect/certs (via the OIDC discovery document). No Keycloak-specific code is needed.
A minimal security configuration to protect all endpoints:
@Configuration@EnableWebSecuritypublic class SecurityConfig {
@Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(auth -> auth .requestMatchers("/public/**").permitAll() .anyRequest().authenticated() ) .oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults())); return http.build(); }}Node with express-oauth2-jwt-bearer
Section titled “Node with express-oauth2-jwt-bearer”express-oauth2-jwt-bearer is Auth0’s MIT-licensed middleware that wraps jose for Express. Install it:
npm install express-oauth2-jwt-bearerimport { auth } from 'express-oauth2-jwt-bearer';import express from 'express';
const checkJwt = auth({ audience: 'my-app-backend', issuerBaseURL: 'http://localhost:8080/realms/my-app',});
const app = express();
app.get('/profile', checkJwt, (req, res) => { res.json({ sub: req.auth?.payload.sub });});The removed Keycloak adapters
Section titled “The removed Keycloak adapters”Keycloak used to ship per-framework adapters: keycloak-connect for Node, a Keycloak Spring Boot adapter, and others. Most of them were removed in Keycloak 25 (the Jetty adapter went a release earlier, in 24), so on a current server they are simply not an option. Use your framework’s standard OIDC/OAuth2 support instead:
| Framework | Recommended library |
|---|---|
| Browser SPA | keycloak-js (official, still maintained) |
| Spring Boot backend | Spring Security OAuth2 Resource Server |
| Node/Express backend | jose or express-oauth2-jwt-bearer |
| Any other backend | Any JWT library that supports JWKS |
Trade-offs
Section titled “Trade-offs”| Option | Benefit | Cost |
|---|---|---|
| Use an official Keycloak adapter (e.g. older keycloak-js, keycloak-connect) | Fast setup, with an API tailored specifically to Keycloak’s own use cases | Tightly coupled to Keycloak — the backend adapters such as keycloak-connect are deprecated, and switching identity provider later is hard |
Implement standard OIDC resource-server middleware yourself (jose, express-oauth2-jwt-bearer, Spring Security’s oauth2ResourceServer) | Portable across any identity provider that supports OIDC/JWKS, and maintained by a broader community | You need to understand the OIDC spec yourself (issuer, audience, JWKS) instead of relying on a vendor-specific abstraction |
Common mistakes
Section titled “Common mistakes”- Trusting client-side auth state instead of verifying at the backend — checking that the frontend has a token, or that the UI shows “logged in,” is not authentication the backend can rely on. Every protected endpoint must go through middleware that actually verifies the JWT, not just trust a header the frontend claims proves the user is logged in.
- Still using a deprecated Keycloak adapter — keycloak-connect and the older Keycloak Spring Boot adapter no longer receive new features. New projects should move to their framework’s standard OAuth2/OIDC resource server support instead.
- Mixing authentication and authorization responsibility into one middleware — checking that a token is valid (authentication) and checking whether the user may access a resource (authorization) should be separate layers. Combining them into one place makes testing and debugging much harder when roles/policy change.
Real-world example
Spring Security’s
oauth2ResourceServer— a production-grade example of using standard middleware instead of a Keycloak-specific adapter; setting just the issuer-uri makes it work with any OIDC-compliant identity provider, not only Keycloak.express-oauth2-jwt-bearer (from Auth0) — built by Auth0, but it can verify Keycloak-issued JWTs just as well, because it follows the OIDC/JWKS standard — a good reminder that solid resource-server middleware shouldn’t be tied to any one vendor.