Keycloak Node.js Connect Adapter
The `keycloak-connect` package provides a Node.js Connect-friendly middleware for integrating applications with Keycloak, an open-source identity and access management solution. It simplifies implementing authentication and authorization using Keycloak for modern applications and services. The current stable version is 26.1.1. However, this package is officially deprecated by the Keycloak project, with plans for removal in the future, and users are advised to seek alternative integration strategies. Key differentiators included its direct integration with the Connect/Express ecosystem, providing session management and protection for routes, but its deprecation signals a shift away from this specific adapter approach in favor of more generic OIDC client libraries. While it offered a streamlined setup for Keycloak, its maintenance and future are uncertain due to the deprecation notice.
Common errors
-
TypeError: Cannot read properties of undefined (reading 'grant')
cause `keycloak.protect()` middleware was not applied to the route, or the session was not correctly initialized, leading to `req.kauth` being undefined.fixEnsure `keycloak.protect()` is invoked as middleware for routes requiring authentication (e.g., `app.get('/protected', keycloak.protect(), (req, res) => { ... })`). Also verify `express-session` and the Keycloak middleware are correctly initialized and ordered before protected routes. -
Error: `keycloak-connect` must be initialized with a session store.
cause The `Keycloak` constructor was called without providing a `store` option, or the provided store was invalid.fixInitialize `keycloak-connect` with an `express-session` compatible store: `const memoryStore = new session.MemoryStore(); const keycloak = new Keycloak({ store: memoryStore }, keycloakConfig);` -
GET /protected 302 -
cause The application is redirecting to the Keycloak authentication server, but the redirect might not be working as expected or the client configuration in Keycloak is incorrect (e.g., invalid redirect URIs).fixCheck your Keycloak client configuration in the Keycloak admin console. Ensure the 'Valid Redirect URIs' for your client includes the exact URL that Keycloak should redirect back to after successful authentication (e.g., `http://localhost:3000/*`). Also, verify the `auth-server-url` in your `keycloak-connect` config is correct.
Warnings
- deprecated The `keycloak-connect` package is officially deprecated by the Keycloak project. It will be removed in the future, and users are strongly advised to migrate to alternative integration methods, likely involving generic OpenID Connect client libraries.
- gotcha Keycloak Connect requires a session store for proper operation, typically `express-session` with a compatible store. Without a properly configured and shared session store, authentication flows (like redirect after login) will fail or users will not maintain their authenticated state.
- breaking Configuration structure and initialization might have subtle changes between major Keycloak versions and corresponding adapter versions. For instance, the expected content of `keycloak.json` or inline configuration objects can vary, especially regarding public vs. confidential clients and SSL settings.
Install
-
npm install keycloak-connect -
yarn add keycloak-connect -
pnpm add keycloak-connect
Imports
- Keycloak
import { Keycloak } from 'keycloak-connect';import Keycloak from 'keycloak-connect';
- Keycloak.middleware
const Keycloak = require('keycloak-connect'); const keycloak = new Keycloak({}); app.use(keycloak.middleware);import Keycloak from 'keycloak-connect'; const keycloak = new Keycloak({}); app.use(keycloak.middleware()); - KeycloakConfig
import type { KeycloakConfig } from 'keycloak-connect';
Quickstart
import express from 'express';
import session from 'express-session';
import Keycloak from 'keycloak-connect';
import path from 'path';
const app = express();
// Session store setup for Keycloak
const memoryStore = new session.MemoryStore();
app.use(session({
secret: process.env.SESSION_SECRET ?? 'superSecretSessionKey',
resave: false,
saveUninitialized: true,
store: memoryStore
}));
// Keycloak configuration (replace with your actual Keycloak client details)
// This example assumes a keycloak.json file is not used and config is inline.
const keycloakConfig = {
realm: process.env.KEYCLOAK_REALM ?? 'myrealm',
'auth-server-url': process.env.KEYCLOAK_AUTH_SERVER_URL ?? 'http://localhost:8080/auth',
resource: process.env.KEYCLOAK_CLIENT_ID ?? 'my-express-app',
'public-client': true,
'ssl-required': 'external',
'confidential-port': 0
};
const keycloak = new Keycloak({ store: memoryStore }, keycloakConfig);
// Mount Keycloak middleware
app.use(keycloak.middleware({
logout: '/logout',
admin: '/admin',
protected: '/protected'
}));
// Define routes
app.get('/', (req, res) => {
res.send('<h1>Public Page</h1><p><a href="/protected">Go to Protected Page</a></p><p><a href="/logout">Logout</a></p>');
});
app.get('/protected', keycloak.protect(), (req, res) => {
res.send(`<h1>Protected Page</h1><p>Welcome, ${req.kauth.grant.access_token.content.preferred_username ?? 'user'}!</p><p><a href="/">Go to Public Page</a></p><p><a href="/logout">Logout</a></p>`);
});
app.get('/login', keycloak.protect(), (req, res) => {
res.send('You should be redirected to Keycloak for login, then back here if successful.');
});
// Error handling for Keycloak
app.use((err: any, req: express.Request, res: express.Response, next: express.NextFunction) => {
if (err && err.name === 'UnauthorizedError') {
return res.status(401).send('Unauthorized');
}
next(err);
});
const PORT = process.env.PORT ?? 3000;
app.listen(PORT, () => {
console.log(`Server running on http://localhost:${PORT}`);
console.log('Ensure Keycloak is running and configured with a client named \'my-express-app\'.');
});