2021-02-20 11:51:44 +01:00
< p align = "center" >
2021-02-27 14:57:49 +01:00
< img src = "https://user-images.githubusercontent.com/6702424/109387840-eba11f80-7903-11eb-9050-db1dad883f78.png" >
2021-02-20 11:51:44 +01:00
< / p >
< p align = "center" >
2021-03-08 02:29:54 +01:00
< i > 🔏 Customize key cloak's pages as if they were part of your App 🔏< / i >
2021-02-20 11:51:44 +01:00
< br >
< br >
2021-03-05 20:43:22 +01:00
< img src = "https://github.com/garronej/keycloakify/workflows/ci/badge.svg?branch=develop" >
< img src = "https://img.shields.io/bundlephobia/minzip/keycloakify" >
< img src = "https://img.shields.io/npm/dw/keycloakify" >
< img src = "https://img.shields.io/npm/l/keycloakify" >
2021-02-20 10:53:26 +00:00
< / p >
2021-02-21 23:06:42 +01:00
2021-03-08 02:29:54 +01:00
< p align = "center" >
2021-03-08 02:54:43 +01:00
< i > Ultimately this build tool Generates a Keycloak theme< / i >
2021-03-08 02:29:54 +01:00
< img src = "https://user-images.githubusercontent.com/6702424/110260457-a1c3d380-7fac-11eb-853a-80459b65626b.png" >
< / p >
2021-02-27 22:49:52 +01:00
2021-02-27 18:19:02 +01:00
# Motivations
2021-02-23 13:11:56 +01:00
The problem:
2021-03-25 12:48:40 +01:00
< p align = "center" >
< i > Without keycloakify:< / i > < br >
< img src = "https://user-images.githubusercontent.com/6702424/108838381-dbbbcf80-75d3-11eb-8ae8-db41563ef9db.gif" >
< / p >
2021-02-23 13:11:56 +01:00
When we redirected to Keycloak the user suffers from a harsh context switch.
2021-02-23 13:14:43 +01:00
Keycloak does offer a way to customize theses pages but it requires a lot of raw HTML/CSS hacking
to reproduce the look and feel of a specific app. Not mentioning the maintenance cost of such an endeavour.
2021-02-23 13:11:56 +01:00
2021-03-08 02:40:25 +01:00
Wouldn't it be great if we could just design the login and register pages as if they where part of our app?
2021-03-05 20:43:22 +01:00
Here is `yarn add keycloakify` for you 🍸
2021-02-23 13:11:56 +01:00
2021-03-24 09:12:04 +01:00
< p align = "center" >
2021-03-24 09:12:50 +01:00
< i > With keycloakify:< / i > < br >
2021-03-24 09:12:04 +01:00
< img src = "https://github.com/InseeFrLab/keycloakify/releases/download/v0.3.8/keycloakify_after.gif" >
< / p >
2021-03-08 02:59:22 +01:00
2021-03-25 12:48:40 +01:00
**TL;DR**: [Here ](https://github.com/garronej/keycloakify-demo-app ) is a Hello World React project with Keycloakify set up.
2021-03-15 16:22:13 +01:00
2021-03-08 02:59:22 +01:00
- [Motivations ](#motivations )
- [How to use ](#how-to-use )
- [Setting up the build tool ](#setting-up-the-build-tool )
- [Developing your login and register pages in your React app ](#developing-your-login-and-register-pages-in-your-react-app )
- [Just changing the look ](#just-changing-the-look )
- [Changing the look **and** feel ](#changing-the-look-and-feel )
- [Hot reload ](#hot-reload )
2021-04-09 03:25:39 +02:00
- [Terms and conditions ](#terms-and-conditions )
2021-03-09 04:56:45 +01:00
- [GitHub Actions ](#github-actions )
2021-03-25 12:48:40 +01:00
- [Requirements ](#requirements )
- [Limitations ](#limitations )
2021-03-26 14:02:14 +01:00
- [`process.env.PUBLIC_URL` not supported. ](#processenvpublic_url-not-supported )
- [`@font-face` importing fonts from the `src/` dir ](#font-face-importing-fonts-from-thesrc-dir )
- [Example of setup that **won't** work ](#example-of-setup-that-wont-work )
2021-03-26 14:04:45 +01:00
- [Workarounds ](#workarounds )
2021-03-26 14:02:14 +01:00
- [Implement context persistence (optional) ](#implement-context-persistence-optional )
2021-03-08 02:59:22 +01:00
- [API Reference ](#api-reference )
- [The build tool ](#the-build-tool )
2021-02-23 13:11:56 +01:00
# How to use
## Setting up the build tool
2021-03-25 12:01:11 +01:00
[`package.json` ](https://github.com/garronej/keycloakify-demo-app/blob/main/package.json )
2021-02-23 13:11:56 +01:00
```json
2021-03-25 12:01:11 +01:00
"homepage": "https://URL.OF/YOUR-APP"
"dependencies": {
2021-03-05 20:43:22 +01:00
"keycloakify": "^0.0.10"
2021-03-08 02:52:58 +01:00
},
"scripts": {
2021-03-11 00:10:34 +01:00
"keycloak": "yarn build & & build-keycloak-theme",
2021-03-08 02:52:58 +01:00
},
2021-02-23 13:11:56 +01:00
```
2021-03-28 14:14:43 +02:00
`"homepage"` must be specified only if the url path is not `/`
(Onl `/YOUR-APP` matters `URL.OF` don't have to be the actual domain)
2021-02-23 13:11:56 +01:00
2021-03-25 12:01:11 +01:00
It is mandatory that you specify the url where your app will be available
using the `homepage` field.
Once you've edited your `package.json` you can install your new
dependency with `yarn install` and build the keycloak theme with
`yarn keycloak` .
2021-03-25 12:48:40 +01:00
Once the build is complete instructions about how to load
the theme into Keycloak are printed in the console.
2021-03-25 12:01:11 +01:00
2021-02-23 13:11:56 +01:00
## Developing your login and register pages in your React app
2021-03-08 02:29:54 +01:00
### Just changing the look
2021-03-25 12:48:40 +01:00
The first approach is to only arr/replace the default class names by your
2021-03-08 02:29:54 +01:00
own.
```tsx
import { App } from "./< wherever > /App";
import {
KcApp,
defaultKcProps,
kcContext
} from "keycloakify";
import { css } from "tss-react";
const myClassName = css({ "color": "red" });
reactDom.render(
// Unless the app is currently being served by Keycloak
// kcContext is undefined.
kcContext !== undefined ?
< KcApp
kcContext={kcContext}
{...{
...defaultKcProps,
"kcHeaderWrapperClass": myClassName
}}
/> :
< App / > , // Your actual app
document.getElementById("root")
);
```
< i > result:< / i >
< p align = "center" >
< img src = "https://user-images.githubusercontent.com/6702424/110261408-688d6280-7fb0-11eb-9822-7003d268b459.png" >
< / p >
2021-03-08 02:35:58 +01:00
### Changing the look **and** feel
2021-03-08 02:29:54 +01:00
If you want to really re-implement the pages the best approach is to
create you own version of the [`<KcApp />` ](https://github.com/garronej/keycloakify/blob/develop/src/lib/components/KcApp.tsx ).
Copy/past some of [the components ](https://github.com/garronej/keycloakify/tree/develop/src/lib/components ) provided by this module and start hacking around.
2021-02-23 13:11:56 +01:00
2021-04-09 04:02:23 +02:00
You can find an example of a fancy customization [here ](https://github.com/InseeFrLab/onyxia-ui/tree/master/src/app/components/KcApp ).
2021-03-08 02:29:54 +01:00
### Hot reload
By default, in order to see your changes you will have to wait for
`yarn build` to complete which can takes sevrall minute.
If you want to test your login screens outside of Keycloak, in [storybook ](https://storybook.js.org/ )
for example you can use `kcContextMocks` .
```tsx
import {
KcApp,
defaultKcProps,
kcContextMocks
} from "keycloakify";
reactDom.render(
kcContext !== undefined ?
< KcApp
kcContext={kcContextMocks.kcLoginContext}
{...defaultKcProps}
/>
document.getElementById("root")
);
```
then `yarn start` ...
2021-03-10 23:55:37 +01:00
Checkout [this concrete example ](https://github.com/garronej/keycloakify-demo-app/blob/main/src/index.tsx )
2021-03-08 02:29:54 +01:00
*NOTE: keycloak-react-theming was renamed keycloakify since this video was recorded*
[](https://youtu.be/xTz0Rj7i2v8)
2021-03-20 05:07:22 +01:00
2021-04-09 03:25:39 +02:00
# Terms and conditions
[Many organizations have a requirement that when a new user logs in for the first time, they need to agree to the terms and conditions of the website. ](https://www.keycloak.org/docs/4.8/server_admin/#terms-and-conditions ).
First you need to enable the required action on the Keycloak server admin console:
2021-04-10 20:20:26 +02:00

2021-04-09 03:25:39 +02:00
Then to load your own therms of services using [like this ](https://github.com/garronej/keycloakify-demo-app/blob/8168c928a66605f2464f9bd28a4dc85fb0a231f9/src/index.tsx#L42-L66 ).
2021-03-20 05:07:22 +01:00
# GitHub Actions
2021-04-11 01:21:01 +02:00

2021-03-20 05:07:22 +01:00
[Here is a demo repo ](https://github.com/garronej/keycloakify-demo-app ) to show how to automate
the building and publishing of the theme (the .jar file).
2021-03-25 12:48:40 +01:00
# Requirements
Tested with the following Keycloak versions:
- [11.0.3 ](https://hub.docker.com/layers/jboss/keycloak/11.0.3/images/sha256-4438f1e51c1369371cb807dffa526e1208086b3ebb9cab009830a178de949782?context=explore )
- [12.0.4 ](https://hub.docker.com/layers/jboss/keycloak/12.0.4/images/sha256-67e0c88e69bd0c7aef972c40bdeb558a974013a28b3668ca790ed63a04d70584?context=explore )
This tool will be maintained to stay compatible with Keycloak v11 and up, however, the default pages you will get
(before you customize it) will always be the ones of the Keycloak v11.
2021-03-20 05:07:22 +01:00
This tools assumes you are bundling your app with Webpack (tested with 4.44.2) .
It assumes there is a `build/` directory at the root of your react project directory containing a `index.html` file
2021-03-25 12:48:40 +01:00
and a `build/static/` directory generated by webpack.
2021-03-20 05:07:22 +01:00
**All this is defaults with [`create-react-app` ](https://create-react-app.dev )** (tested with 4.0.3=)
- For building the theme: `mvn` (Maven) must be installed
2021-03-25 12:48:40 +01:00
- For development (testing the theme in a local container ): `rm` , `mkdir` , `wget` , `unzip` are assumed to be available
2021-03-20 05:07:22 +01:00
and `docker` up and running.
NOTE: This build tool has only be tested on MacOS.
2021-03-25 12:48:40 +01:00
# Limitations
2021-03-26 14:02:14 +01:00
## `process.env.PUBLIC_URL` not supported.
2021-03-20 05:07:22 +01:00
2021-03-26 14:02:14 +01:00
You won't be able to [import things from your public directory in your JavaScript code ](https://create-react-app.dev/docs/using-the-public-folder/#adding-assets-outside-of-the-module-system ). (This isn't recommended anyway).
2021-03-20 05:07:22 +01:00
2021-03-26 14:02:14 +01:00
## `@font-face` importing fonts from the `src/` dir
### Example of setup that **won't** work
- We have a `fonts/` directory in `src/`
2021-03-26 14:04:45 +01:00
- We import the font like this [`src: url("/fonts/my-font.woff2") format("woff2");` (https://github.com/garronej/keycloakify-demo-app/blob/07d54a3012ef354ee12b1374c6f7ad1cb125d56b/src/fonts.scss#L4 ) in a `.scss` a file.
2021-03-26 14:02:14 +01:00
2021-03-26 14:04:45 +01:00
### Workarounds
2021-03-26 14:02:14 +01:00
If it is possible, use Google Fonts or any other font provider.
If you want to host your font recommended approach is to move your fonts into the `public`
directory and to place your `@font-face` statements in the `public/index.html` .
2021-04-09 03:25:39 +02:00
Example [here ](https://github.com/InseeFrLab/onyxia-ui/blob/0e3a04610cfe872ca71dad59e05ced8f785dee4b/public/index.html#L6-L51 ).
2021-03-26 14:02:14 +01:00
You can also [use your explicit url ](https://github.com/garronej/keycloakify-demo-app/blob/2de8a9eb6f5de9c94f9cd3991faad0377e63268c/src/fonts.scss#L16 ) but don't forget [`Access-Control-Allow-Origin` ](https://github.com/garronej/keycloakify-demo-app/blob/2de8a9eb6f5de9c94f9cd3991faad0377e63268c/nginx.conf#L17-L19 ).
2021-03-20 05:07:22 +01:00
2021-03-25 12:48:40 +01:00
# Implement context persistence (optional)
2021-03-20 04:59:18 +01:00
If, before logging in, a user has selected a specific language
you don't want it to be reset to default when the user gets redirected to
the login or register pages.
Same goes for the dark mode, you don't want, if the user had it enabled
to show the login page with light themes.
The problem is that you are probably using `localStorage` to persist theses values across
reload but, as the Keycloak pages are not served on the same domain that the rest of your
app you won't be able to carry over states using `localStorage` .
The only reliable solution is to inject parameters into the URL before
redirecting to Keycloak. We integrate with
[`keycloak-js` ](https://github.com/keycloak/keycloak-documentation/blob/master/securing_apps/topics/oidc/javascript-adapter.adoc ),
by providing you a way to tell `keycloak-js` that you would like to inject
some search parameters before redirecting.
The method also works with [`@react-keycloak/web` ](https://www.npmjs.com/package/@react-keycloak/web ) (use the `initOptions` ).
You can implement your own mechanism to pass the states in the URL and
restore it on the other side but we recommend using `powerhooks/useGlobalState`
from the library [`powerhooks` ](https://www.powerhooks.dev ) that provide an elegant
way to handle states such as `isDarkModeEnabled` or `selectedLanguage` .
Let's modify [the example ](https://github.com/keycloak/keycloak-documentation/blob/master/securing_apps/topics/oidc/javascript-adapter.adoc ) from the official `keycloak-js` documentation to
enables the states of `useGlobalStates` to be injected in the URL before redirecting.
Note that the states are automatically restored on the other side by `powerhooks`
```typescript
import keycloak_js from "keycloak-js";
import { injectGlobalStatesInSearchParams } from "powerhooks/useGlobalState";
import { createKeycloakAdapter } from "keycloakify";
//...
const keycloakInstance = keycloak_js({
"url": "http://keycloak-server/auth",
"realm": "myrealm",
"clientId": "myapp"
});
keycloakInstance.init({
"onLoad": 'check-sso',
"silentCheckSsoRedirectUri": window.location.origin + "/silent-check-sso.html",
"adapter": createKeycloakAdapter({
"transformUrlBeforeRedirect": injectGlobalStatesInSearchParams,
keycloakInstance
})
});
//...
```
2021-03-08 02:29:54 +01:00
2021-03-20 04:59:18 +01:00
If you really want to go the extra miles and avoid having the white
flash of the blank html before the js bundle have been evaluated
[here is a snippet ](https://github.com/InseeFrLab/onyxia-ui/blob/a77eb502870cfe6878edd0d956c646d28746d053/public/index.html#L5-L54 ) that you can place in your `public/index.html` if you are using `powerhooks/useGlobalState` .
2021-03-26 14:02:14 +01:00
# API Reference
## The build tool
Part of the lib that runs with node, at build time.
2021-03-28 14:14:43 +02:00
- `npx build-keycloak-theme` : Builds the theme, the CWD is assumed to be the root of your react project.
2021-03-26 14:02:14 +01:00
- `npx download-sample-keycloak-themes` : Downloads the keycloak default themes (for development purposes)