Remix Auth Keycloak Strategy

2.0.4 · active · verified Wed Apr 22

remix-keycloak is an authentication strategy for Remix applications, specifically designed to integrate with Keycloak identity and access management. It extends the `remix-auth` library's `OAuth2Strategy` to provide a robust solution for authenticating users via a Keycloak instance. Maintained by Cybernite Intelligence, this package serves as a direct successor and active continuation of the now-archived `remix-auth-keycloak`. The current stable version is 2.0.4. While there isn't a fixed release cadence, updates are made as needed to ensure compatibility with Remix v1 and v2, and to address Keycloak-related changes. A key differentiator is its commitment to supporting multiple runtimes, including Node.js, Cloudflare Workers, and Netlify functions, making it versatile for various deployment environments. It simplifies the setup of Keycloak-based authentication flows, including client ID/secret handling, callback URLs, and token management within a Remix context.

Common errors

Warnings

Install

Imports

Quickstart

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",
//   });
// };

view raw JSON →