Step up authentication with Angular customised route guard

Hi there,

I’m trying to configure step-up 2FA authentication in an Angular app using:

I want the step-up authentication to happen every time (ie max age 0) a user tries to access specific Angular routes. I have discovered that the canActivateAuthGuard() functions provided by @okta/okta-angular do not support checks of the max age, only the ACR value. Consequently the path forward is a custom auth guard function.

I created the custom function & configured a route to use it.

When a user attempts to access the route they get challenged for a 2FA (Okta verify). However, the user never gets returned to the target route. Instead they end up in a constant loop being prompted for the 2FA (Okta Verify). I’ve provided a copy of the custom auth guard code below.

Any suggestions/assistance would be greatly appreciated.

Thanks

-------------------------

export const canActivateStepUpGuard: CanActivateFn = async (route, state) => {

  const oktaAuth = inject(OKTA_AUTH);

  // Check if the user is authenticated
  const isAuthenticated = await oktaAuth.isAuthenticated();
  if (!isAuthenticated) {
    oktaAuth.setOriginalUri(state.url);
    await oktaAuth.signInWithRedirect();
    return false;
  }

  // Get the user's ID token
  const idToken = oktaAuth.getIdToken();
  if (idToken == undefined) {
    oktaAuth.setOriginalUri(state.url);
    await oktaAuth.signInWithRedirect();
    return false;
  }

  // Check that the authentication time is recent enough
  const tokenClaims = oktaAuth.token.decode(idToken);
  const authTime = tokenClaims.payload.auth_time;
  const currentTime = Math.floor(Date.now() / 1000);
  if (!authTime || (currentTime - authTime) > 60) {
    // If the authentication time is too old, force step-up authentication  
    oktaAuth.setOriginalUri(state.url);
    await oktaAuth.signInWithRedirect(
      {
        acrValues: "urn:okta:loa:2fa:any",
        maxAge: 60,
        originalUri: state.url
      }
    );
    return false;
  }
  return true;
}

One further detail I just noticed…

It appears that the ID token auth_time is not being updated during the step up authentication process. I tried setting maxAge to 1 & also setting prompt to login in the signInWithRedirect() call but the auth_time did not change.

Hi,

Your loop isn’t caused by Okta failing to refresh auth_time — it’s the guard checking the wrong claim. Per Okta’s step-up authentication guide, the claim that confirms step-up succeeded is acr, not auth_time.

auth_time records when the original authentication happened and isn’t guaranteed to change on every step-up round trip the way your (currentTime - authTime) > 60 check assumes. That’s why it stayed flat even after you switched to maxAge: 1 and prompt: ‘login’ — you were reading a claim that was never meant to signal "step-up just completed.

Could you please rewrite your code to check acr against your required Level of Authentication instead of auth_time age?

Thanks,

Ashutosh

Hi Ashutosh,

Thanks for the info.

Any chance you can provide a link to the step-up auth guide you’re referring to?

Thanks for the tip on auth_time not being modified on step-up - I thought I had read somewhere that it does get updated if you make the call to signInWithRedirect() & include the prompt=login option.

I need a way to validate the age of the acr claim so that if it’s older than x then call signInWithRedirect(). From what I can see, once you have called signInWithRedirect() with the acrValues option the acr claim remains & is not cleared.

Any suggestions?

Hi Tim,

You can use the below documentation for Step-up authentication and it’s implementation using Angular:

Thanks,

Ashutosh

Hi Ashutosh,

Thanks - I’ve already read both of those articles. They do not provide any details on how to check the age of an acr claim.

Do you have any suggestion on how to validate the age of the acr claim?

Thanks again

Hi @tim2026 !

Welcome to the community!

You are correct, the current canActivateAuthGuard() only support acr, but I highly recommend creating an issue against the Okta Angular library requesting this feature if you require it.

I haven’t tried looking at evaluating max_age step up checks client-side, only in the resource server against the access token. I’ll try to take a look at the id token when I can (but warning you it might be a bit before I can get to it).

Just in case, here’s my demo app showing authn recency check in an Angular + .NET API where I poked at this scenario a bit for a talk I gave.

Let us know if you are able to figure things out!