Keycloak Reactjs demo with silent check-sso feature and PKCE

For all interested:

I’ve updated my Keycloak Reactjs demo to the latest Keycloak version 8.x with the silent check-sso feature (this is NOT silent refresh for (insecure) implicit flow!) and PCKE support.

3 Likes

@dasniko that’s fantastic, thanks for sharing. Would be nice to see something like this for our quickstarts https://github.com/keycloak/keycloak-quickstarts?

@abstractj Thanks, I’ll have a look into the quickstarts project. Don’t know how it will fit into my current sparetime. But perhaps step by step…

@dasniko i have configured the silent chek sso on my project but it is being redirected to the keyclaok website for getting the user status. but according to the silent check sso it shouldn’t redirect to the keycloak website to fetch the status. can you help me to resolve the issue

  1. Don’t post the same problem in multiple posts. (you did already ask for help in Keycloak- silent check sso is not working)
  2. Provide a minimum working example where one can reproduce your problem. Just saying “it doesn’t work” is just not enough.

@dasniko thanks for responding actually we used the configuration of keycloak js like below on the screenshot

and we used the browser as chrome version 89.

but we are not able to find out where the issue is. can you help us

@dasniko Thank you for the React demo. It has helped me at my current workplace. Do you have other demos which demonstrate how to add a custom field in the keycloak login/signup page? My use case in particular requires adding a country code dropdown in the keycloak form. Thank you in advance.

Sorry, for your usecase I don’t have any demo.
Adding custom attributes to register is handled here: Server Developer Guide
If you need to handle custom attributes during login, consider that you most probably also need a custom authenticator which handles the custom attribute, not only a customized theme!!

@dasniko - thank you for your demo and video tutorial.
I’m having some issues implementing the silent-check-sso feature, and hope that you could help me with some pointers in the right direction.

Our keycloak integration differs from your example example in that it’s written as a React component, “keycloak-provider”. That component include some state hooks like isAuthenticated, initialized, etc. along with some handlers for refreshing the token, updating state, Init and errors. It’s very similar to this component, tough not written in typescript:
https://github.com/react-keycloak/react-keycloak/blob/master/packages/core/src/provider.tsx

Adding silentCheckSsoRedirectUri: ${window.location.origin}/silent-check-sso.html along with the neccesary file at /public/silent-check-sso.html, seem to make the keycloak.login() function instantly redirect back to the current (public/unauthenticated) page before authentication has taken place. I’ve been inspecting the return value from createLoginUrl() which looks correct. I’m not sure the code at the silent-check-sso.html is ever executed, i’ve tried registering an eventlistener for the message, but can’t seem to catch any events.

Do silent-check-sso require some additional configuration of the KC server? For development purposes I have valid redirectUri specified as “*”, but other than that…?
Are there some caveats around implementing silent-check-sso as a react provider component?

Would be very greatful for any insights and remedies you may have for this behaviour.

EDIT 1:
it seems the redirect issue above comes from beeing logged in while toggling the silent-check-sso feature. Logging out before enabling it makes the login page appear correctly. Login in through the login page redirects the user back to the app, but it seems the token is not captured correctly and the keycloak-instance in the client has “authenticated: false” and does not return a token field.

I still can’t see any messages from the silent-check-sso.html when adding an event-listener to the location.href message. I’ve also tried to add the postMessage to a react component at /silent-check-sso route in the app, along with some debug-messages, but I still can’t see any logging printed to the console.

I tried it like that as we’re using reach-router in the project, and adding pages to public seem to return “Cannot GET: [pagename]”.

*EDIT 2:
…continuing the search I can now confirm that the token is set in an iframe upon submitting the authentication form. Previously, we had “checkLoginIframe” set to false, and then there was no iframe in the application. The documentation states that I should not get the token directly from the cookie, but it’s not present on the keycloak-client instance, so something is still wrong about this config. As stated earlier - greatful for any pointers in the right direction.

*EDIT 3:
As it turns out I had a too restrictive security policy on the server using “frame-ancestors ‘self’” that blocked the iframe at /silent-check-sso from working out. Now the authentication works, altough not perfectly yet, but the very same issue I set out to solve remains - all the site scripts and assets are still downloaded twice, before authentication and then after the redirect. The only difference is that no “silent-check-sso” is listed as the initiatior for all of the second round of downloads instead of “index” beeing the initiator of all of them. It seems there is a final piece to the puzzle… still greatful for any help.

@dasniko I followed everything step by step… but I keep getting loading application… I even cloned the one on your github you added on youtube and updated the url to my own, but it’s same thing. can you please help me if possible

@M3rtzi has stated in great detail whatever i have been facing, i wonder if you manage to find a solution for this.

It’s now working after I downgraded my keycloak-js and react-keycloak/web version… BUT it’s now resetting everything to undefined after like 5secs. any help will be grateful.

have you tried only using the default adapter (keycloak-js)

No… I used react-keycloak/web and default adapter (keycloak-js)

import Keycloak from "keycloak-js";

const keycloak = new Keycloak({
  url: "my url/",
  realm: "my realm",
  clientId: "my client id",
})

export default keycloak;
import React, { useEffect } from 'react';
import {
  BrowserRouter as Router,
  Routes, Route
} from "react-router-dom"
import Nav from "./components/Nav";
import WelcomePage from "./pages/Homepage";
import SecuredPage from "./pages/Securedpage";
import PrivateRoute from "./helpers/PrivateRoute";
import { KeycloakProvider  } from "@react-keycloak/web";
import keycloak from "./Keycloak"

const App = () => {
  return (
    <div>
      <KeycloakProvider keycloak={keycloak}>
        <Nav />
        <Router>
          <Routes>
            <Route
              path="/secured"
              element={
                <PrivateRoute>
                  <SecuredPage />
                </PrivateRoute>
              }
            />
            <Route exact path="/" element={<WelcomePage />} />
          </Routes>
        </Router>
      </KeycloakProvider>
    </div>
  )
}

export default App;

and then

import React from "react";
import { useKeycloak } from "@react-keycloak/web";

const Nav = () => {
  const { keycloak } = useKeycloak();

  console.log('KEYCLOAK', keycloak.token)
  
  return (
  <div>
      <h1>
        NMCN V2.0
      </h1>
      

      {!keycloak.authenticated && (
        <button
          type="button"
          className="text-blue-800"
          onClick={() => keycloak.login()}
        >
          Login
        </button>
      )}

      {!!keycloak.authenticated && (
        <button
          type="button"
          className="text-blue-800"
          onClick={() => keycloak.logout()}
        >
          {/* ({keycloak.tokenParsed.preferred_username}) */}
          Logout 
        </button>
      )}

      <ul>
        <li>
          <a href="/">
            Home
          </a>
        </li>
        <li>
          <a href="/secured">
            Secured Page
          </a>
        </li>
      </ul>
    </div>
  );
};

export default Nav;

Refused to frame ‘http://localhost:8080/’ because an ancestor violates the following Content Security Policy directive: “frame-ancestors ‘self’”.

any idea how to bypass this the correct way

no… but can you share your code here, lemme have a look

1 Like

i figured it out as well, its just that once i am logged in the first value is false, but when i move between the pages, everything works perfectly fine

Can you please help and share with me your configuration codes and the packages/version you used ? cos my keycloak properties are becoming undefined after like 5 seconds. Thank you.

give me your discord let me help you out