Unlimited Refresh Token - site never auto-logs out

Hi,

I’ve been experimenting with the refresh token to try and get my SPA app to automatically log out after a certain time limit.
It’s been successful if I specify a limited time refresh token ie

However if I specify an unlimited refresh token it never logs out. In fact the only way I can
tell that the token is invalid is anytime I submit a request to my backend (django) authorization server and I get a token error.

Is there anything I have to do differently with my app in order to make this work? Right now everything regarding the token validation is handled under the hood so I’m not actually doing anything differently to log out if I specify a limited refresh token lifetime.

Happy to share whatever extra info I can. I’m just not sure what is pertinent in this case.

My front-end is using okta-auth-js and okta-react.

Thanks!

Just bumping this to see if anyone has any insight.

Particularly if someone could explain what would happen if, for instance, my settings were:

I would take this to mean that after 5 minutes the access token expires but the refresh token is used to get a new access token. This refresh token will never expire unless the app(?) is used every 10 minutes?

This is where I get a bit confused - but will expire if not used every is a bit vague. What is being used?

If i set the refresh token lifetime to 10 minutes instead of unlimited, the app logs out after about 20 minutes or so - kinda what I’m expecting.

So what should happen in the case of an unlimited token?

Thanks again!

Hello @BirdThunderford,

If,
access_token = 5 minutes
refresh_token = unlimited
but_will_expire = 10 minutes

Then the access_token always is only good for 5 minutes.
The refresh_token will never expire if it is used at least once every 10 minutes to get a new access_token. Once it is used the 10 minute window starts over.
I there is ever a period where 12 minutes has elapsed since the last time the refresh_token was used to get an access_token it will no longer be valid.

Also note that if the refreh_token lifetime was set to 1 hour instead with the other settings the same. Even if the refresh_token was used every 8 minutes after 1 hour it sill would be invalid at that point.

Thank You,

Thanks for getting back to me.

So from what I’m experiencing, it looks like my app is checking for an access token every 5 minutes:

Screen Shot 2022-12-15 at 4.41.08 PM

Which from the access token lifetime settings seems to make sense.

So each time it calls back to check the token, its using that unlimited refresh token to authenticate against.

Each time this happens the refresh token restarts the 10-minute clock.

So if I never leave this page it will never log me out?

Now if I leave the page, and wait a bit and come back, it does prompt me to log back in but I never have to put in my password.

It just doesn’t behave the same way that having a limited refresh token does (logging me out completely after the refresh token expires). So perhaps I’m just misunderstanding what’s supposed to happen if I have an unlimited refresh token. I don’t see the point of the but will expire if not used every option if it never actually invalidates the refresh token.

Hi!

I am a bit confused by your question. Specifically what you mean by auto-logging out of the SPA, and that the “authorization server” is where you get a token at Okta, your backend would be the “resource server”? But taking my best guess this may help you:

The only purpose of a refresh token is to obtain an updated access token. When a refresh token expires that does not log the user out of your Okta org. So the purpose of an access token is to prove to the resource server (your web service, API, backend…) that the client application is authorized to do certain operations (the scopes). The access token has nothing to do with the concept of being “logged in”, and in fact could expire AFTER the Okta session has already expired. And again, an access token expiring does not log the user out of your Okta org.

If you are trying to force a logout of the SPA, just clear your token cache and when the user tries to do something the SPA will have to get a new token again. If they still have a session at Okta they don’t have to re-authenticate. If you are trying to force them to log out of the Okta org then in the SPA dump the token cache and use the “sessions” API at Okta to terminate their session at the org.

1 Like

Apologies. I was mixing my terminology. Yes, I meant resource server.

I should probably restate my intentions as well. I’d like to have the application log the user out if it sits idle for too long or generally has been logged in for a certain period of time.

There’s a lot of settings in the okta dashboard that I think should be what I need to set but in setting them I don’t actually know if I’m causing more trouble than I’m resolving.

My apps settings:

I also added a sign-on policy for the app that looks like this:
image

I’ve also set up an access policy in the security API:

As far as my code, its pretty boilerplate okta-auth js.

import { Component, Fragment, lazy, Suspense } from 'react';
import { Switch, Route, Router } from 'react-router-dom';
import * as ReactDOMClient from "react-dom/client";

import { Security, LoginCallback, SecureRoute } from '@okta/okta-react';
import { OktaAuth, toRelativeUrl } from '@okta/okta-auth-js';

import { CacheProvider } from '@emotion/react';
import createCache from '@emotion/cache';

import { createBrowserHistory } from 'history';

import Box from "@mui/material/Box";

import LoadingIcon from './common/components/LoadingIcon';

const Home = lazy(() => import('./apps/Main/Home'));
const Login = lazy(() => import('./apps/Main/Login'));

const history = createBrowserHistory();
const cache = createCache({
  key: 'a-key',
  nonce: __webpack_nonce__,
  prepend: true,
});

const config = {
  issuer: process.env.OKTA_ISSUER,
  clientId: process.env.OKTA_CLIENT_ID,
  redirectUri: window.location.origin + '/oidc/callback',
}

class App extends Component {
  constructor(props) {
    super(props);
    this.oktaAuth = new OktaAuth(config);
    
    this.restoreOriginalUri = async (_oktaAuth, originalUri) => {
      props.history.replace(toRelativeUrl(originalUri, window.location.origin));
    };

    this.authRedirect = (oktaAuth) => {
      history.push('/login');
    };
    
  }

  render() {
    return (
      <Security
        oktaAuth={this.oktaAuth} 
        restoreOriginalUri={this.restoreOriginalUri}
        onAuthRequired={this.authRedirect}
      >
        <CacheProvider value={cache}>
          <Box
            id='app-root-container'
            sx={{
              display: 'flex',
              flexDirection: 'column',
              height: '100vh',
              m: -1,
            }}
          >
            <Fragment>
              <Suspense fallback={<LoadingIcon />}>
                <Switch>
                  <SecureRoute exact path='/' component={Home} />
                  <Route exact path='/login' component={Login} />
                  <Route exact path='/oidc/callback' component={LoginCallback} />
                </Switch>
              </Suspense>
            </Fragment>
          </Box>
        </CacheProvider>
      </Security>      
    );
  }
}

const container = document.querySelector("#app");
const root = ReactDOMClient.createRoot(container);
root.render(
  <Router history={history}>
    <App history={history} />
  </Router>
);

I have my primary route as secure route and let okta-auth-js do all the work.
Perhaps I misunderstood what okta-auth-js is doing because I figured I could have the app log out after a certain amount of time by just making configurations in the okta app dashboard. But again, maybe I set something that’s cancelling something else out. I’m honestly not sure.

In the end all I want to do is determine that a user has gone past a certain amount of idle or login time and the app logs out. If its something I have to do in code, that’s fine. I just need to know what piece of the puzzle I’m missing.

Hope this helps to clarify.

Thanks!

I’m continuing to experiment with this and I think I understand what the unlimited refresh token is referring to. What I am confused by still is that if an access token lifetime is shorter than the refresh token is longer than this, that refresh token will always be used anytime the access token needs to be renewed.

So in what case will an unlimited refresh token ever be invalid?

I tried some new settings just to see what happens when I define a finite refresh token:

And I think i see what’s happening. Once the refresh token expires I get

OAuthError: the refresh token is invalid or expired

But what I’d prefer to do is catch this error so I can log out gracefully. Is there any way I can do this?

I’m doing something like

authClient.on('error' (key) {
  console.log(key)
});

to determine what was failing. So I guess I’m not sure what exactly is going on to force the logout but I’d like to be able to stop it before it happens.

Any thoughts?