Why is the keycloak instance not returned corectly using a pinia store (keycloak-js)?

Here is a code part of my pinia store, with which I try to abstract the authentication:
The code works for authentication, and I can read the token in other parts via
useAuthStore.istance.token correctly.


export const useAuthStore = defineStore('auth', {
    state: () => ({
        instance: null as Keycloak
    }),
    getters: {
        token() {
            return this.instance.token
        }
    },
    actions: {
        setInstance(instance: Keycloak) {
            this.instance = instance
        },
        async tryAuthentication() {
            const kinstance = new Keycloak()

            return kinstance.init({
                enableLogging: true,
                checkLoginIframe: true,
                onLoad: "check-sso",
                silentCheckSsoRedirectUri: window.location.origin + '/silent-check-sso.html',

            })
                .then(function (authenticated) {
                    if (authenticated) {
                        useAuthStore().setInstance(kinstance)
                        console.log(kinstance) //here I have the field: idTokenParsed
                        console.log("keycloak after init: ", useAuthStore().instance) //here I don't have it
                    } else {
                        location.href = kinstance.createLoginUrl();
                    }
                })
                .catch((e) => {
                    console.log(`keycloak init exception ${e}`);
                })
        },
...

My Problem is, that when I checkout the instance of keycloak right in the then() section, I can get fields like idTokenParsed, which I cannot read just in the next line, when I get the instance from the store.

Fun fact: the pinia store, when I check the store in the dev-tools, has the fields
BUT: when I try to refresh the token, in the same store:

async refreshToken() {

            console.log(this.instance) //fields are missing again
            console.log("Token was not refreshed, still valid?:" + this.instance.isTokenExpired(180))
//throws error: not authenticated, because the fields are missing in that instance...

            await this.instance.updateToken(180)
                .then((refreshed: any) => {
                    if (refreshed) {
                        console.log("Token was refreshed")
                    } else {
                        console.log("Token was not refreshed")
                    }
                })
                .catch(() => {
                    console.log("Cannot refresh token")
                })
        }
    }

I cannot do that, as the fields required are missing …
What did I get wrong?

Somehow I cannot correctly, write and access the instance after init() with its values after a correct authentication…

I haven’t reviewed the code, but keep in mind that the upcoming deprecation of third-party cookies will impact:

  • OpenID Connect Front-Channel Logout
  • OpenID Connect Session Management
  • iframe-based background token renewal :point_left:
  • iframe-based login widget

This means your code will likely break if it relies on iframes.

As a alternative, I recommend reviewing the RFC (draft) OAuth 2.0 for Browser-Based Applications [1], which provides guidelines for architecture patterns in public clients. Alternatively, you always have the option to delegate the authentication and token renewal to a proxy with an OIDC module such as lua-resty-openidc [2].

[1] draft-ietf-oauth-browser-based-apps-19
[2] GitHub - zmartzone/lua-resty-openidc: OpenID Connect Relying Party and OAuth 2.0 Resource Server implementation in Lua for NGINX / OpenResty