githubEdit

arrow-up-to-dotted-lineMigrating from Keycloak-js

Polyfilling keycloak-js with oidc-spa

If you're using keycloak-jsarrow-up-right in an existing codebase, you can migrate to oidc-spa without a painful rewrite. oidc-spa ships a keycloak-js polyfill. It’s a drop-in replacement.

It's not an exhaustive poliffils, some knobs have been intentionally removed to align with current best practices. For example, this implementation of the keycloak-js surface won't let you use the implicit or hybrid flow and won't let you disable PKCE.

chevron-rightWhy switch?hashtag

Security

UX

  • Auto Logout: optional “You will be logged out in 30…29…” overlay. No more “submit → redirect to login” because the Keycloak session expired.

  • Login/Logout propagation across tabs.

  • Much faster and relyable SSO, especially in non ideal condition (iframe blocked / Keycloak not on same site, slow network...)

1

Update dependency

Replace keycloak-js with oidc-spa in your package.json.

package.json
 {
     dependencies: {
-        "keycloak-js": "...",
+        "oidc-spa": "..."
     }
 }
2

Update your codebase

-import Keycloak from "keycloak-js";
+import { Keycloak } from "oidc-spa/keycloak-js";
-import KeycloakAuthorization from "keycloak-js/authz";
+import { KeycloakAuthorization } from "oidc-spa/keycloak-js-authz";

 // ...

 await keycloak.init({
     onLoad: 'check-sso',
-    silentCheckSsoRedirectUri: `${location.origin}/silent-check-sso.html`,
     //NOTE: fragment will be used. Conflict with your app logic routing
     //is structuraly impossible in oidc-spa so there is no reason to 
     //support query.
-    responseMode: "query",
     // ...
 });
 
// In oidc-spa the auth state is immutable and can be either:
// - Not established yet:   keycloak.didInitialize is false
// - User is logged in:     keycloak.authenticated is true
// - User is not logged in: keycloak.authenticated is false
// The value of keycloak.authenticated will never change without a full app reload.
// If you want to redirect to a specific page after logout call:
// keycloak.logout({ redirectUri: "/bye" })
-keycloak.onAuthLogout(()=> {});

// With oidc-spa you'll never end-up in a state where calling this makes sense.
-keycloak.clearToken();

// oidc-spa handles this internally.
-keycloak.onAuthRefreshError(); 

Delete public/silent-check-sso.html.

3

(OPTIONAL) Fix your Valid Redirect URIs

Log in to the Keycloak Admin Console. Open your client configuration.

 Valid Redirect URIs:
  http://localhost*
- https://dashboard.my-company.com/*
- https://dashboard.my-company.com/silent-check-sso.html
+ https://dashboard.my-company.com/ (Note: The trailing `/` is important)
4

Enable Security Features

If you're moving to oidc-spa, you likely want to enable DPoP and other security features.

Pick the setup option that best fits your project:

If you're in a Vite project, the recommended approach is to use oidc-spa’s Vite plugin.

vite.config.ts
import { defineConfig } from "vite";
import { oidcSpa } from "oidc-spa/vite-plugin";

export default defineConfig({
    plugins: [
        // ...
        oidcSpa({
            // See: https://docs.oidc-spa.dev/v/v10/security-features/browser-runtime-freeze
            browserRuntimeFreeze: {
                enabled: true
                //exclude: [ "fetch", "XMLHttpRequest"]
            },
            // See: https://docs.oidc-spa.dev/v/v10/security-features/dpop
            DPoP: {
                enabled: true,
                mode: "auto"
            }
        })
    ]
});

You can enable keycloak.init({ enableLogging: true }) to see a console report for the security features.

5

(OPTIONAL) Display a Warning Before Auto Logout

oidc-spa implements auto logout by respecting the idle session lifetime you configured in Keycloak.

To warn the user when they are about to be logged out due to inactivity, you can show an overlay like: “Are you still here? Your session will expire in 30…29…”

Get the underlying oidc-spa core object like this:

import { Keycloak } from "oidc-spa/keycloak-js";

const keycloak = new Keycloak({ ... });

await keycloak.init({ 
    ...
    
    // Optionally, customize the behavior of where the user gets redirected
    // when their session expires.  
    // autoLogoutParams: { redirectTo: "current page" } // Default
    // autoLogoutParams: { redirectTo: "home" }
    // autoLogoutParams: { redirectTo: "specific url", url: "/your-session-has-expired" }
    // autoLogoutParams: { 
    //      redirectTo: "specific url", 
    //      get url(){ return `/your-session-has-expired?return_url=${encodeURIComponent(location.href)}`; }
    // }
});

// You can only access this property after keycloak.init() has resolved.
const oidc = keycloak.oidc;

Then implement the overlay as described here: Displaying a Warning Before Auto Logout.

6

You're Done 🎉

If you run into some issue do not hesitate to reach out on Discordarrow-up-right.

Last updated

Was this helpful?