keycloakify / oidc-spa

Openid connect client for Single Page Applications
https://www.oidc-spa.dev
MIT License
48 stars 6 forks source link

Provide error handling for init error #14

Closed Nichtmetall closed 7 months ago

Nichtmetall commented 7 months ago

Hey, I would like to specify a function that should be executed if initialization fails. For example, if the openid-configuration call throws an error. It would be great if I can get the error via useOidc(). :D

garronej commented 7 months ago

Hello @Nichtmetall,

Thank you for your inputs!
Yes there is needs to improve the error handling.
Currently, the expected beaviour (but there is a bug) is the following:
If the OIDC server is down or misconfigured an error get printed in the console, everything continues as normal with the user unauthenticated. If the user tries to login an alert saying that authentication is not available at the moment is displayed and nothing happens. This enable your the part of your app that do not requires authentication to remain up even when your identities server is facing issues.

Anyway I'm open to add an extra parameter that would enable to implement custom error handling somehow.
On the useOidc it seems like it would mess up the typing. How do you see it? Can you describe what you want to acheive?

Woudln't a fallback error node as a props of the cut it? I mean if it was called with the error object.

Nichtmetall commented 7 months ago

Hello @garronej , Thank you very much for the great project. I used react-oidc-provider before. That's exactly what I was looking for.

In my use case there is the problem that the keycloak realm is read out via the subdomain. However, a subdomain can also be entered there without this realm existing. Due to the 404 of the openid-configuration I know that the realm does not exist. Now I would like to redirect to a 404 error page via react-router-dom. Unfortunately, I cannot react to this event.

A fallback parameter in the provider would be an option for me. However, I would already display this fallback node if it is detected when the call against the openid-configuration throws an error.

Thank you very much!

garronej commented 7 months ago

Hold on, I think I've found a solution that might work for you. I'll release a candidate version shortly, and you can let me know what you think.

Considering you don't seem to be from the French public service, given that I haven't promoted this library yet, I'm curious about how you discovered it. You mentioned you were using react-oidc-provider. Could you share what aspects of this library influenced your decision to switch? Was it because it's easier to set up, it includes setup examples, the enhanced TypeScript support, or the ability to bypass React when you need to? Understanding this would help me articulate a stronger value proposition in the README. Thanks!

Nichtmetall commented 7 months ago

Thank you very much! You are my hero.

Yes, I'm actually from Germany. :D I came across you via the keycloakify-starter template. I saw that the provider there comes from this library. And I was looking for a new one because react-oidc-context was too unreliable for me. I'm a fan of simple setups and standardized functions such as renewTokens(). In react-oidc-context, for example, you had to handle this yourself. In addition, the setup is very simple and intuitive. It works quickly and reliably. In addition, the other library had a few bugs, such as that if no realm was found, you got into a loop of about 1000 calls / 10s.

But just as a question: Are you very experienced with Keycloak?

Nichtmetall commented 7 months ago

Btw great work you did here. 👍🏻

garronej commented 7 months ago

Thank you for your feedback on your experience! I'll use your insights to update the README.

Also, I appreciate your recognition of our efforts! I've just released a new version with significantly improved error management during initialization. Please check it out and let me know if it meets your needs: https://docs.oidc-spa.dev/getting-started/usage#error-management I've aimed to simplify the complexity as much as possible.

Regarding your question about Keycloak experience:

While I consider myself knowledgeable enough to recognize my limitations, I am the creator of Keycloakify and am developing software (https://onyxia.sh/) that extensively utilizes Keycloak. (However, Onyxia can also integrate with other identity servers). I also have the privilege of collaborating with experts in this area, which help stay on top of things.

Nichtmetall commented 7 months ago

Super! That sounds great.

I'll test the new version now and give you feedback later.

That sounds great as I have a question regarding SSO Session Idle. We have often tried to trigger an automatic logout when the session idle has expired. However, as the token is continuously renewed, Keycloak is not notified of the idle. How have you implemented this?

Kind regards!

garronej commented 7 months ago

That sounds great as I have a question regarding SSO Session Idle. We have often tried to trigger an automatic logout when the session idle has expired. However, as the token is continuously renewed, Keycloak is not notified of the idle. How have you implemented this?

You'll have to describe more precisely what's the exact behaviour you want to acheive. You want to automatically logout your user after a set period of inactivity on the app (they do not touch the keyboard or mouse)?

Nichtmetall commented 7 months ago

That sounds great as I have a question regarding SSO Session Idle. We have often tried to trigger an automatic logout when the session idle has expired. However, as the token is continuously renewed, Keycloak is not notified of the idle. How have you implemented this?

You'll have to describe more precisely what's the exact behaviour you want to acheive. You want to automatically logout your user after a set period of inactivity on the app (they do not touch the keyboard or mouse)?

Yes exactly! Thats it. Nothing more special.

Nichtmetall commented 7 months ago

Wow! It works perfectly. Just as I thought it would. :D

garronej commented 7 months ago

Yes exactly! Thats it. Nothing more special.

Yes, so this is something that you would implement on the client side. You can have a timeout that, when exhausted, calls the oidc.logout() function. You'd clear this timeout and reschedule it every time a "mousemove" or "keydown" is registered on the window.document.

A nice addition would be to make sure not to clear and schedule the timeout hundreds of times a second when the user scrolls, for example, allowing a delay before you start listening again after an event is detected.

GPT4 implementation of this approach:

import { prOidc } from "oidc";

prOidc.then(oidc => {
    if (!oidc.isUserLoggedIn) {
        return;
    }

    const idleDelayBeforeLogoutMs = 30_000;
    let timer;

    const logoutIfIdle = () => {
        clearTimeout(timer); // Clear the existing timer
        timer = setTimeout(() => {
            oidc.logout();
        }, idleDelayBeforeLogoutMs);
    };

    // Initial call to set the logout timer
    logoutIfIdle();

    // Event listeners to reset timer on user activity
    window.document.addEventListener("mousemove", logoutIfIdle, false);
    window.document.addEventListener("keydown", logoutIfIdle, false);
});
Nichtmetall commented 7 months ago

Thank you very much man! I appreciate this very much!

garronej commented 7 months ago

Note that the gpt implementation works but the debounce implementation is stupid as it produce just as much work!

garronej commented 7 months ago

@Nichtmetall on secon though, it's not the responsability of the client to define security policy such as the idle timeout.
I think this is a usecase that oidc-spa should handle.
There should be a parameter like preventRefreshIfUserInactive or something like that. I should read the expiration time from the JWT trigger the logout internally when I know the token has expired.
I'm going to make some experimentation with that and come out with a solution.
I will also update the usage with keycloak documentation page to tell what parameter needs to be set on the Keycloak side.

garronej commented 6 months ago

Hey @Nichtmetall,

oidc-spa now support auto logout and provide an easy way to display a countdown timer.
https://docs.oidc-spa.dev/documentation/auto-logout