Allow the user to change their password from a profile screen

This question has been asked before here but not answered as far as I can tell. I want a “Change password” link on the user’s profile page on my app, where the user can change their password without going through the reset-by-email workflow from the login screen. This is pretty much a typical convention on almost every website in the world, and yet doesn’t seem to be an option out-of-the-box in Auth0. Is it possible, and if it’s a planned future feature, is it coming soon?

1 Like

Hi @wwarby! Welcome to the Auth0 Community.

This can be accomplished using the the Management API /api/v2/tickets/password-change endpoint. This endpoint responds with a password change URL.

Let me know if you have any questions about it or if this doesn’t solve your problem.

Thanks dan, I gave that a quick test and I can get a valid response back and change a password. However, when I tried to call that API in the context of the user authenticated to my app, I get a 401 response and I see that when assigning roles to users, the option togrant permissions on the management API is not there. Do I need to proxy this request through my own server using a machine-to-machine connection? I can do that, it just seems a bit of a faff for something that feels like it should really be out-of-the-box .

Were you able to get any requests to the management API working from your application? What framework are you using to make requests to the management API? And if possible could you post the code you use to get the access token (please omit sensitive data i.e. domain, client ID, client secret etc.)

If you haven’t yet, take a look at this resource that will walk you through setup for the management API:

Thanks,
Dan

Hi Dan,

So I’m using Angular, and my code is tracking fairly closely to the Angular QuickStart from Auth0. It’s using the NPM package auth0-js and calling something like this (simplified for clarity) but nothing important lost here):

// Normal page load:
auth0 = new WebAuth({
    clientID: environment.auth0.clientID, //Key from the dashboard
    domain: environment.auth0.domain, // My auth0 hosted subdomain
    responseType: 'token id_token',
    redirectUri: environment.auth0.callbackURL, // http://localhost:4200/callback
    audience: environment.auth0.audience, // Path to my app's API
    scope: this._requestedScopes // "openid profile email read:permission1 readpermission1... etc"
  });
auth0.authorize();

// Callback page load:
auth0.parseHash(async(err, authResult) => {
  if (authResult && authResult.accessToken && authResult.idToken) {
    this.storeAuthResult(authResult);
  }
});

This all works fine - I can get a user, logged in, and I can make calls to my own API and read the user’s profile etc, so this is how I tried to implement the behaviour behind a “Change Password” button on my user profile screen:

public async changePasswordAsync() {
    const response = await this.http.post<{ticket: string}>(`${auth0ApiBase}tickets/password-change`, {
      result_url: environment.auth0.callbackURL,
      connection_id: environment.auth0.dbConnectionId,
      email: this.profile.email,
      mark_email_as_verified: true
    }).toPromise();
    if (response.ticket) {
      window.location.href = response.ticket;
    }
}
// Note: an Angular HTTP Interceptor is adding the Authorization header in the format `Bearer {authResult.accessToken}` to the post request.

All the parameters are definitely correct because I’ve tested the exact set of parameters using the API explorer and got a result. The difference is the bearer token - from the API explorer I was using a machine-to-machine token and in the Angular app I was using the token derived from authenticating a real user in the app itself.

Thanks for the response.

You will be unable to reach that management API endpoint in a single page application. This is due to the insecure nature of a SPA. We recommend that all calls to the management API be done via a non-interactive client (your backend). We have management api libraries for most common backends. I can point you in the right direction if you let me know what language/framework you are using.

Please let me know if this helps :smile: !

A bit more on it in this topic:

Thanks Dan, I kinda figured that’s where this was headed but I appreciate the clear response. It’s a .NET core app on the back end and I’m pretty sure I know what I need to do to proxy the request through that. I get why it is the way it is because the change password link has to be generated with a limited time horizon so at least the way your service is configured right now, it’s a call into an API to get the link and it makes sense that that API isn’t exposed to JavaScript clients given how easily it could be abused. However, I can’t shake the feeling that what’s on offer here is a little less than optimal. It is surely a very common use case that an authenticated user wants to change their password - and not just because they’ve forgotten it. It seems like there should be a way to send the user to a page where they can do that (entering their current password first of course) without the need for me to implement an API, which calls your API, which gets a link, which I must then redirect the user to, before they can do the password change. It all feels a little convoluted for a fairly simple scenario.

To be fair though, this (and the inability to change a user’s name, which I understand is imminently about to be released) are the only two gripes I have with an identity service that otherwise has come together very smoothly for me, so thanks :slight_smile:

@wwarby Thanks for the constructive criticism as well as the positive feedback! The hoops we jump through for security’s sake!

Here is the relevant SDK: Documentation

Also, getting community feedback is extremely important, and most effective if submitted here. I would be happy to submit something on your behalf if you DM me your name and email so the dev team can contact you if they have questions/comments.

Thanks!

Okay, I’m 99% of the way there with this now - generating the URL server-side using a machine-to-machine connection and redirecting the user to it client-side, they can reset their password. The only snag is it doesn’t redirect them back to the application after they do - instead they just get a “your password has been changed” page.

I’ve set result_url to http://localhost:4200 which is where my Angular app is running, and I’ve set that as a valid URL in the allowed callback URLs for both the machine-to-machine application and the SPA application. What have I missed?

Are you getting any errors in the console or anywhere else? I am trying to replicate the issue but everything is working okay over here.

If you want to record a HAR file I can take a look at that.

I thought I knew what the problem was. From https://auth0.com/docs/universal-login/default-login-url:

In certain cases (described below), Auth0 could need to redirect back to the application’s login initiation endpoint, using OIDC Third Party Initiated Login … When the password reset flow is completed and the default URI for the application or tenant is configured, users will see a button that will let them navigate back to the login page. This behavior only happens when the New Universal Login Experience is enabled.

I do have the new universal login experience enabled, and I didn’t have a default login URL configured. However I’ve now set that up (albeit to a production URL that doesn’t exist because I’m still developing on localhost), and it doesn’t seem to have made any difference. I’ll make you a HAR file shortly…

This topic was automatically closed 15 days after the last reply. New replies are no longer allowed.