0
votes

I've been trying with little success to implement the token refresh using the oidc-client library. Any help or insight is greatly appreciated.

Stack:

  • React
  • GraphQL (Apollo Client)

Structure:

I've tried a few approaches, starting with automaticSilentRenew and creating a static-renew.html callback file in my public/ folder - but this both approaches gave me a No state in response error so I set out on a workaround.

Workaround:

I'm wrapping the router in a component which does the following:

  • on mount it calls oidc-client.getUser()and then adds the following listeners:

    • oidcMgr.events.addAccessTokenExpiring(handleTokenExpiring)
    • window.addEventListener('message', this.handleSilentRenew)
  • When the addAccessTokenExpiring event first fires it calls a function that: oidcMgr.createSigninRequest({ redirect_uri: process.env.REACT_APP_SILENT_REDIRECT_URI }) and sets the response to local state using apollo-link-state

  • Renders the iFrame when there is a tokenURI in apollo-link-state (from the function above).

  • When the component unmounts it removes both listeners.

  • When the callback URL is hit, it mounts a component that posts a message with the source silent-renew so the listener mounted in step 1 can set the token URI to '' in apollo-link-state thus terminating the iframe and calls getUser again.

This works for refreshing the token but it seems that the iFrame is loading the entire application inside of it, and then terminating, causing the application to consume more resources than necessary.

Is there another, more straightforward way to use this library to refresh the token within a React application? Any help or perspective will be greatly appreciated. Thank you!

2
What does your static-renew.html has? it should typically load, oidc-client js and one function to handle signinCallback, - hashbytes

2 Answers

0
votes

This might give you some heads up in the approach you are using,

I have used some different approach to initate the silentRenw, instead of using

automaticSilentRenew: true,

I decided to explicitly call the signInSilent();. Reason for doing the i was facing some issues as automaticSilentRenew: true, was not working as expected.

I initialized the event and method in my UserAuth class constructor that implements my interface

constructor(private oidcSettings: CoreApi.Interfaces.Authentication.OpenIDConnectionSettings)
{
 this.userManager.events.addAccessTokenExpiring(() =>
         {
            this.userManager.signinSilent({scope: oidcSettings.scope, response_type: oidcSettings.response_type})
                    .then((user: Oidc.User) =>
                    {
                        this.handleUser(user);
                    })
                    .catch((error: Error) =>
                    {
                       //Work around to handle to Iframe window timeout errors on browsers
                        this.userManager.getUser()
                            .then((user: Oidc.User) =>
                            {
                                this.handleUser(user);
                            });
                    });
            });
}

Where as handleUser is just check for logged in user.

So if you initialize the signInSilent process in your constructor and then call signInSilent complete i.e. callback it may work.

0
votes

What does your static-renew.html has? it should typically load, oidc-client js and one function to handle signinCallback, Once the sign in callback handled well, it emits an event UserLoaded, that is where your parent need to update the user object (access_token, id_token)