Install & Compatibility
Where this runs
tested against v? · npm install
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
muslnode 18–226 runs
build_error
glibcnode 18–226 runs
build_error
Code
Verified usage
Verified import paths — ran on the pinned version, not inferred.
KeycloakStrategy
✓ import { KeycloakStrategy } from 'remix-keycloak'
✗ import { Keycloak } from 'remix-auth-keycloak'
The strategy class for Keycloak. Ensure you import from 'remix-keycloak', not the old 'remix-auth-keycloak' package.
Authenticator
✓ import { Authenticator } from 'remix-auth'
remix-keycloak integrates with remix-auth; Authenticator is imported from 'remix-auth', not remix-keycloak itself. This is standard for remix-auth strategies.
loader
✓ export let loader: LoaderFunction = ({ request }) => { /* ... */ }
Remix loaders handle GET requests. When setting up callback routes, the loader will typically be used for the initial authentication success/failure redirect.
action
✓ export let action: ActionFunction = ({ request }) => { /* ... */ }
Remix actions handle POST requests. The action is used to initiate the Keycloak authentication flow, usually via a form submission.
This quickstart demonstrates how to set up `KeycloakStrategy` with `remix-auth`, configure environment variables, and define the authentication and callback routes required for a complete Keycloak login flow in a Remix application. It also shows a basic `User` interface and session storage setup.
import { Authenticator } from "remix-auth";
import { KeycloakStrategy } from "remix-keycloak";
import { createCookieSessionStorage } from "@remix-run/node";
interface User {
id: string;
email: string;
name: string;
}
// Create a session storage for the authenticator
const sessionStorage = createCookieSessionStorage({
cookie: {
name: "_session",
sameSite: "lax",
path: "/",
httpOnly: true,
secrets: [process.env.SESSION_SECRET ?? 'super-secret-key'],
secure: process.env.NODE_ENV === "production",
},
});
export const authenticator = new Authenticator<User>(sessionStorage);
const keycloakStrategy = new KeycloakStrategy(
{
useSSL: process.env.KEYCLOAK_USE_SSL === 'true',
domain: process.env.KEYCLOAK_DOMAIN ?? 'your-keycloak-domain.com',
realm: process.env.KEYCLOAK_REALM ?? 'your-realm',
clientID: process.env.KEYCLOAK_CLIENT_ID ?? 'your-client-id',
clientSecret: process.env.KEYCLOAK_CLIENT_SECRET ?? 'your-client-secret',
callbackURL: process.env.KEYCLOAK_CALLBACK_URL ?? 'http://localhost:3000/auth/keycloak/callback',
},
async ({ accessToken, refreshToken, extraParams, profile }) => {
// In a real application, you would typically find or create a user in your DB
// based on the profile data from Keycloak.
console.log("Keycloak Profile:", profile);
console.log("Access Token:", accessToken);
// For this example, we'll return a mock user
return {
id: profile.id || profile.emails?.[0]?.value || 'anonymous',
email: profile.emails?.[0]?.value || 'user@example.com',
name: profile.displayName || 'Keycloak User'
};
}
);
authenticator.use(keycloakStrategy, "keycloak");
// Example route: app/routes/login.tsx
// export default function Login() {
// return (
// <form action="/auth/keycloak" method="post">
// <button>Login with Keycloak</button>
// </form>
// );
// }
// Example route: app/routes/auth/keycloak.tsx
// import type { ActionFunction } from "@remix-run/node";
// import { authenticator } from "~/utils/auth.server"; // Adjust path as needed
// export let action: ActionFunction = ({ request }) => {
// return authenticator.authenticate("keycloak", request);
// };
// Example route: app/routes/auth/keycloak/callback.tsx
// import type { LoaderFunction } from "@remix-run/node";
// import { redirect } from "@remix-run/node";
// import { authenticator } from "~/utils/auth.server"; // Adjust path as needed
// export let loader: LoaderFunction = ({ request }) => {
// return authenticator.authenticate("keycloak", request, {
// successRedirect: "/dashboard",
// failureRedirect: "/login",
// });
// };
Errors
Common errors & fixes
Error: Response not found for strategy "keycloak"
This usually indicates that the `authenticator.authenticate` call in your Remix action or loader is not correctly configured or the strategy name ('keycloak' by default) doesn't match.
fixEnsure that `authenticator.use(keycloakStrategy, "keycloak")` is called with the correct strategy name and that the `authenticator.authenticate("keycloak", request, ...)` calls in your routes also use `"keycloak"`. TypeError: Cannot read properties of undefined (reading 'authenticate')
The `authenticator` instance was not properly initialized or exported/imported in the file where it's being used.
fixVerify that `export const authenticator = new Authenticator<User>(sessionStorage);` is in a server-side utility file (e.g., `app/utils/auth.server.ts`) and is correctly imported into your route files.
Keycloak: Invalid client or redirect URI
This error originates from the Keycloak server and means there's a mismatch in the `clientID`, `clientSecret`, or `callbackURL` provided by your Remix application and what Keycloak expects.
fixDouble-check the `clientID`, `clientSecret`, and `callbackURL` in your `KeycloakStrategy` configuration against your Keycloak client settings. Pay close attention to trailing slashes and case sensitivity for the URL.
Audit
Dependencies
@remix-run/server-runtimerequiredRequired by Remix for server-side utilities and request handling.