Alex Sokoloff
Alex Sokoloff

Reputation: 81

Silent token renewal with react-oidc-context without page refresh

I have been trying to get silent token refreshes to work using react-oidc-context. This package is built on top of oidc-client-ts. My application uses react-router. By default silent token renewal is turned on with react-oid-context. With this setup, the page reloads about a minute before the token expires - not a great user experience. The token does get renewed - the new token with a new expiration date is stored in session storage, which I believe is the source of truth for calls to get the token from react-oidc-context.

My understanding is that, to perform a silent token renewal, oidc-client-ts attaches an iframe to the page and loads a page inside it from your authority / authentication provider. This does not occur with the default setup for react-oidc-context. I can get it to work, partially, by sidestepping the react app: by pointing the silent_redirect_uri config variable to a page outside the react app and triggering the logic for the silent token renewal in that page. The basic idea is described here:

https://stackoverflow.com/questions/43938570/adding-silent-renew-entry-point-to-reactcreate-react-app/44022621#44022621

My config for react-oidc-context:

const oidcConfig = {
    client_id: <AUTH_LOCK_KEY>,
    redirect_uri: window.location.origin + '/loading-handler',
    silent_redirect_uri: window.location.origin + '/silent-renew',
    authority: <SSO_URL>,
    automaticSilentRenew: true,
    onSigninCallback,
}

My script at /silent-renew/index.html:

      <script src="oidc-client.min.js"></script>
      <script>
        function inIframe() {
                try {
                    return window.self !== window.top
                } catch (e) {
                    return false;
                }
        }

        if (inIframe()) {
            console.log("in iframe")
        } else {
            console.log("not in iframe")
        }
        new Oidc.UserManager({
            authority: <SSO_URL>,
            client_id: <AUTH_LOCK_KEY>,
            redirect_uri: window.location.origin,
        }).signinSilentCallback().then(r => console.log(r))
    </script>

This works up to a point. There is no page refresh, a page loads in the iframe, and a call goes out to the authority which returns a HTTP 200. There seems to be a token in a set-cookie from the server. However, the token in local session storage doesn't update. Also, oidc-client-ts keeps trying every 30 seconds or so to perform the silent renewal. So, how can I refresh the token without a page refresh?

Upvotes: 5

Views: 10837

Answers (1)

curious.netter
curious.netter

Reputation: 814

I had the same issue. I need to revoke the token on addAccessTokenExpiring event.

  useEffect(() => {
    return auth.events.addAccessTokenExpiring(() => {
    auth.revokeTokens();
   })   
 }, [auth.events]);

My authentication server is IdentityServer3. I am using a React app (with React-Router-6) as a client with a .Net 6 Web Api using 'Access Token' to get data from an 'authorized' end-point.

If you need more clarification/code, let me know.

Upvotes: 1

Related Questions