Auth0 "Password Rotation" Action incorrect redirect with expired password

I have a username/password database being used for authentication in a React web application. I want to require an end user to cycle their password if it is over 90 days old.

I implemented the Password Rotation Action documented here Force a password reset after X days

However the hosted UI at https://{my-tenant}.us.auth0.com via the Universal Login (we aren’t using the classic custom UI feature) does not handle the case where a user needs to reset their password.

My expectations were that the Password Rotation action would redirect to the hosted UI which would have a state displaying to the user to reset their password.

What happens is that after entering in my username and password it redirects to

https://{my-tenant}.us.auth0.com/authorize/resume?state={state variable}

which then redirects to

https://{my-server-domain}/?error=access_denied&error_description=Your%20password%20has%20expired.%20%20Please%20reset%20it.&state={state variable}

So you can see it redirects out of a flow that touches the hosted UI and tries to have my web server handle the password reset which seems incorrect.

I’m trying to find the source code for this action to see what is the intended flow.

Does anyone have experience with this Action?

Hi @adam20,

Welcome to the Auth0 Community!

I have just checked all of your tenants under your subscription account and found that none of them have the Force a password reset after X days Action deployed and bound to the Post-Login Action flow.

Could you please make sure that you have clicked on the “Add to flow” option? You can do this by going to the Auth0 Dashboard > Actions > Library and clicking on the triple-dot icon and selecting “Add to flow”:

Please make sure to click on “Apply” to save your changes once you have added it to the Post Login flow.

Thanks,
Rueben

Hi @rueben.tiow,

I did have Password Retention as part of our flow, but because we use the tenant for our test servers I had to take it out as it prevented any user with an expired password from authenticating and would get caught in that loop described above.

My description of the issue above is with Password Retention applied as part of our flow while I was testing it, then I took it out after I was finished.

Hi @adam20,

Thanks for following up.

I have just checked your Password Rotation script’s configuration and see that you have the Password Expiry in Days set to 1 and not 90, which is your preferred number of days.

Let me also emphasize that this Action will only apply to users who authenticate with a Database Connection:

Reference: https://marketplace.auth0.com/integrations/auth-0-password-rotation

Therefore, if you are using a different type of connection to authenticate, this Action will not force the user to reset their password.

Thanks Ruben, again the current settings were just those I was playing around with. Our same situation described above happens regardless of the period of time in days it is set to.

I experimented setting the Expiry in Days to 1 day to force the flow of needing to reset the password. Which again did not work as I kept getting redirected as described above.

From what I can tell the flow is broken or something about how we are using Auth0 in react maybe?

It would be helpful if I could view the source code for the Password Rotation login action. Could you point me to that?

1 Like

Hi All,

I’m encountering the exact same issue.
Properly configured the Password Rotation integration and as soon as i did, it is stuck in an endless loop with the invalid redirect URL.

Appreciate your assistance here.

Thanks,
Udi

Hi @adam20,

Thanks for following up.

I have just tested the login flow with the Password Rotation built-in Action and can confirm that everything is working as expected.

Whenever a user tries to log in with an expired password, they get redirected to a URL like the following: https://{yourDomain}/?error=access_denied&error_description=Your%20password%20has%20expired.%20%20Please%20reset%20it.&state={state variable}

Here is a screenshot of a network trace: image

This is by design, and this requires the user to restart the login flow again to get to the login page and then follow up with the “Forgot Password?” option.

I hope the explanation was clear.

Thanks,
Rueben

Hi @udib,

If you are experiencing an endless loop, this happens because the user still has an active session.

In this case, you should consider passing the prompt=login query parameter to force the user to re-authenticate on the Universal Login page.

For example:

https://{yourDomain}/authorize?
    response_type=code&
    client_id={yourClientId}&
    redirect_uri={https://yourApp/callback}&
    scope={scope}&
    audience={apiAudience}&
    state={state}&
    prompt=login

(Reference: New Universal Login Experience)

Thanks,
Rueben

1 Like

Hi @rueben.tiow ,
Thank you for your prompt response!
I’m assuming you mean the ‘Customize Login Page’ section, please correct me if i’m wrong.
This option is disabled on our tenants, is there any other way to force users to re-authenticate?

Thanks,
Udi

Hi @udib,

Thanks for the reply.

I do not mean the ‘Customize Login Page’ section. I mean passing the prompt=login in your login request.

You will need to adjust your authorization parameters for your login call to include 'prompt=login`. This will depend on the SDK you are using. Note that this will always force your users to re-authenticate.

One other possibility would be to have a mechanism to have these users log out so that they can re-authenticate. Or having the session be as short-lived as possible.

Thanks,
Rueben

For my issue I am using the React SDK with the Auth0Provider component. It does not have a configuration for the prompt directly. The only mention of it I see is here https://github.com/auth0/auth0-spa-js/blob/f9d33040b432cdb2990f46085c9286c25497fe31/src/global.ts#L156 .

I am using username/password via a database for logging in and not an IDP. I set the timeouts for my tokens to be very short and removed them from the browser cache then waited longer than needed for everything to expire and the endless loop still occurs.

So I don’t think that setting the prompt would resolve the issue as I can guarantee there are no valid refresh or access tokens for the test user I am experiencing this with.

Regarding the proper use of this action is it documented anywhere? This confuses me.

yourDomain - does this refer to the domain I actually own or my Auth0 domain.

For example if I own the domain www.MyWebsite.com and I lets say an auth0 domain of mywebsite-auth0.com where my Auth0 Universal login UI is hosted.

Shouldn’t the Password Rotation action redirect the end user to the Hosted UI at my Auth0 domain mywebsite-auth0.com?

Right now it is redirecting them to my application’s domain aka www.MyWebsite.com?error=access_denied&error_description=Your%20password%20has%20expired.%20%20Please%20reset%20it.&state={state variable}

Hi @adam20,

Thanks for following up.

When using the React SDK, you can specify the prompt=login as an authorizationParams in the loginWithRedirect() method. In this situation, you will want to handle the login error by redirecting the user back to the login page if the “access_denied” error occurs.

For example:

const options = {
  prompt: 'login'
}
await loginWithRedirect(options);

(Reference: AuthorizationParams | @auth0/auth0-react)

Please let me know if you have any questions.

Thanks,
Rueben

Oh I see, am I correct in assuming the Auth0 action Password Rotation’s purpose is to return an access_denied error with a message string and you have to manually handle it on the front end.

I was under the assumption that the redirect from Password Rotation would be handled by the Auth0Provider React component to open the Universal Login taking the user to the Password Reset screen (shown below) with the error_description param describing why the error was thrown being shown to the user in the universal login screen.

I added prompt: 'login' to loginWithRedirect, it does fix the endless loop by bringing the user back to the login screen. But it does not take them to the “Reset your password” screen. There is no notice to the user that the reason they authenticated successfully but are still at the login screen is due to an old password.

If the above assumptions are true is it possible to somehow bring the user to the Password Reset view in the Universal Login with a message?

Hi @adam20,

That is the expected behavior. The Password Rotation does not redirect the user to the Password Reset screen. Instead, the user must click on the “Forgot Password” option when they are redirected back to the login page to initiate the password reset flow.

I hope that is clear!

Thanks,
Rueben

Ah I see, so this was working as intended I was just not aligned on what the designed flow was.

Is there a way to redirect a user to the Reset Password screen in the Universal Login hosted UI with a custom message? Or would that have to be handled in our web application?

Right now the user doesn’t know to reset their password because nothing is indicating the error.

Hi @adam20,

Unfortunately, there is no way to redirect the user to the Password Reset screen. The response below in a related community topic answers this question:

The error is shown when they try to log in, and they are instructed to reset their password before continuing. The password reset page will not show the error, because it only allows them to set a new password. There are no checks happening during this stage.

Thanks,
Rueben

Can you please clarify what you mean by this? (A screenshot would be helpful)

I do not see in the Hosted UI any error shown to the end user that the login failed due to an expired password.

The redirect url does contain the text, but this URL does not actually get handled by the react <Auth0Provider> component and only shows a white screen before my application calls loginWithRedirect and brings them back to the starting login screen (with no error message)

example URL: https://{my-server-domain}/?error=access_denied&error_description=Your%20password%20has%20expired.%20%20Please%20reset%20it.&state={state variable}

Hi I was wondering if you could provide some final clarification to the question above?

Hi @adam20,

Thanks for the replies.

When the user tries to log in, they will see this error in the URL: https://{my-server-domain}/?error=access_denied&error_description=Your%20password%20has%20expired.%20%20Please%20reset%20it.&state={state variable}

The user will continue to see the error in the URL until they have reset their password.

And that is the intended user experience? That a non-technical end user would need to know to visually parse the URL in a query string for an error message?

My assumption is then that the Password Rotation action is not intended for web applications, especially those that utilize the Universal Hosted UI by Auth0?