In your Webpack Project
If you have a Webpack/React/TypeScript project you can integrate Keycloakify directly inside it.
In this guide we're going to work with a vanilla Create React App project.


Let's start by installing Keycloakify (and optionally Storybook) to our project:
yarn add keycloakify
yarn add --dev rimraf storybook @storybook/react @storybook/react-vite
Next we want to repatriate the relevant files from the starter template into our project:
cd my-app
git clone https://github.com/keycloakify/keycloakify-starter-webpack tmp
mv tmp/src src/keycloak-theme
mv tmp/.storybook .
rm -rf tmp
rm src/keycloak-theme/react-app-env.d.ts
mv src/keycloak-theme/index.tsx src/index.tsx

Now you want to modify your entry point so that:
If the kcContext global is defined, render your Keycloakify theme
Else, render your App as usual.
Let's say, for example, your src/index.tsx file currently looks like this:
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import { MyProvider } from "./MyProvider";
import reportWebVitals from './reportWebVitals';
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
);
root.render(
<React.StrictMode>
<MyProvider>
<App />
</MyProvider>
</React.StrictMode>
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
You want to rename this file to src/index.app.tsx (for example) and modify it as follow:
import './index.css';
import App from './App';
import { MyProvider } from "./MyProvider";
import reportWebVitals from './reportWebVitals';
export default function AppEntrypoint(){
return (
<MyProvider>
<App />
</MyProvider>
);
}
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
Then you want to create the following src/index.tsx file, you can copy paste the following code, it does not need to be adapted:
import { createRoot } from "react-dom/client";
import { StrictMode, lazy, Suspense } from "react";
import { KcPage, type KcContext } from "./keycloak-theme/kc.gen";
const AppEntrypoint = lazy(() => import("./index.app"));
// The following block can be uncommented to test a specific page with `yarn dev`
// Don't forget to comment back or your bundle size will increase
/*
import { getKcContextMock } from "./keycloak-theme/login/KcPageStory";
if (import.meta.env.DEV) {
window.kcContext = getKcContextMock({
pageId: "register.ftl",
overrides: {}
});
}
*/
createRoot(document.getElementById("root")!).render(
<StrictMode>
{window.kcContext ? (
<KcPage kcContext={window.kcContext} />
) : (
<Suspense>
<AppEntrypoint />
</Suspense>
)}
</StrictMode>
);
declare global {
interface Window {
kcContext?: KcContext;
}
}
Finally you want to add some script for Keycloakify in you package.json and also let Keycloakify know about how your Webpack project is configured.
{
"name": "my-app",
"scripts": {
"prestart": "keycloakify update-kc-gen && keycloakify copy-keycloak-resources-to-public",
"start": "react-scripts start",
"prestorybook": "npm run prestart",
"storybook": "storybook dev -p 6006",
"prebuild": "keycloakify update-kc-gen",
"build": "react-scripts build",
"postbuild": "rimraf build/keycloakify-dev-resources",
"build-keycloak-theme": "npm run build && keycloakify build",
"format": "prettier . --write"
// ...
},
"keycloakify": {
"accountThemeImplementation": "none",
"projectBuildDirPath": "build",
"staticDirPathInProjectBuildDirPath": "static",
"publicDirPath": "public"
},
// ...
Keycloakify has many build options that you can use, however projectBuildDirPath
, staticDirPathInProjectBuildDirPath
and publicDirPath
are parameters specific to the use of Keycloakify in a Webpack context.
Theses are not preferences! If you're not using Create React App your Webpack configuration is probably different and you want to update those values to reflect how webpack build your site in your project.

npm run build
the app distribution is generated in a build/ directory, this is why we use "projectBuildDirPath": "build"
. We can also see that all the assets of the app are gathered under a static/
directory this is why we use "staticDirPathInProjectBuildDirPath": "static"
. And finally we can see that everything we put in the public/ directory is copied over to the build/ directory when building so we use "publicDirPath": "public"
.Last step is to exclude from your html <head />
things that aren't relevant in the context of Keycloak pages.
Do not blindly copy paste, this is just an example!
You have to figure out what does and does not make sense to be in the <head/> of your Keycloak UI pages.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/icon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<link rel="apple-touch-icon" href="%PUBLIC_URL%/icon.png" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" />
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
<meta name="keycloakify-ignore-start">
<title>ACME Dashboard</title>
<script>
window.ENV = {
API_ADDRESS: '${API_ADDRESS}',
SENTRY_DSN: '${SENTRY_DSN}'
};
</script>
<meta name="keycloakify-ignore-end">
<!-- ... -->
</head>
<!-- ... -->
In the above example we tell keycloakify not to include the <title>
because keycloakify will set it dynamically to something like "ACME- Login" or "ACME - Register".
We also exclude a placeholder script for injecting environment variables at container startup.
That's it, your project is ready to go! 🎉
You can run npm run build-keycloak-theme
, the JAR distribution of your Keycloak theme will be generated in build_keycloak
(you can change this).
You're now able to use all the Keycloakify commands (npx keycloakify --help
) from the root of your project.
If you're currently using keycloak-js or react-oidc-context to manage user authentication in your app you might want to checkout oidc-spa, the alternative from the Keycloakify team.
If you have any issues reach out on Discord! We're here to help!
Last updated
Was this helpful?