skip to Main Content

I am writing an API for user to reset self password. User is logged in an web application which calls MS Graph API.

While trying to self update password(I need to verify the current password too), I am getting below error:

code":"Authorization_RequestDenied","message":"Access to change password operation is denied."

Below is my code:

 private static async Task UpdatePassword(string clientId, string clientSecret, string tenantId)
    {
        try
        { 
            var scopes = new string[] { "https://graph.microsoft.com/.default" };

            // Configure the MSAL client as a confidential client
            var confidentialClient = ConfidentialClientApplicationBuilder
                .Create(clientId)
                .WithAuthority($"https://login.microsoftonline.com/{tenantId}/v2.0")
                .WithClientSecret(clientSecret)
                .Build();

           
            GraphServiceClient graphServiceClient =
                new GraphServiceClient(new DelegateAuthenticationProvider(async (requestMessage) =>
                {

                // Retrieve an access token for Microsoft Graph (gets a fresh token if needed).
                    var authResult = await confidentialClient
                .AcquireTokenForClient(scopes)
                .ExecuteAsync();

                // Add the access token in the Authorization header of the API request.
                    requestMessage.Headers.Authorization =
                new AuthenticationHeaderValue("Bearer", authResult.AccessToken);
                })
                ); 

            await graphServiceClient.Users["9c704dfb-a3ea-528a-937c-d7da45ebcc7a"]
                .ChangePassword("OldPassword", "NewPassword").Request().PostAsync(); 

        }catch(Exception e)
        { 
        }
    }

I also saw /me endpoints but did not understand how to make that work in my scenario.

I appreciate any help, Thank you.

2

Answers


  1. Your requirement: Writing an API for user to reset self password.

    Background: User is logged in an web application which calls MS Graph API.

    If you want to create a stand alone web api which exposing a feature to let users update their password, it is impossible. Let’s see the api document, it doesn’t support application api permission. Pls note, application type not support means you can’t write an api project to provide the ability because web api project is considered as a daemon application which only support AAD client credential flow, and client credential flow must use application permission. According your code snippet, you set the scope as xxx/.default, this means you are trying to use client credential flow.

    enter image description here

    We can only use Delegated api permission. According to the screenshot in your this question, we can see you’ve given the Directory.AccessAsUser.All, so I consider you’ve had enough permissions. You can’t realize this feature in a stand-alone api project, but you can do it in the web application which allows users to sign in by AAD.

    Here’s a sample for users sign in by integrating AAD into the web application. And I think you should have similar code in your web app(providing a login partial view, modify Startup.cs file and add configurations in appsettings.json), what you need to do is following the sample to add code about Graph SDK.

    services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
                    .AddMicrosoftIdentityWebApp(Configuration)
                    .EnableTokenAcquisitionToCallDownstreamApi(initialScopes)
                    .AddMicrosoftGraph(Configuration.GetSection("DownstreamApi"))
                    .AddInMemoryTokenCaches();
    

    enter image description here

    And in your Controller, inject GraphServiceClient graphServiceClient and change password with code await graphClient.Me.ChangePassword(currentPassword,newPassword).Request().PostAsync();

    Login or Signup to reply.
  2. I agree with @Tiny Wang. Although I have done the same via postman and it’s just a different approach to the solution of your issue.

    To change user’s password, you must add Delegated Directory.AccessAsUser.All permission for your application.

    Please note that, the code you mentioned is using Client credentials flow that works with only Application permissions.

    I tried to reproduce the same in my environment and got below results:

    I granted below API permissions to the Azure AD application in my B2C tenant:

    enter image description here

    Now I generated access token using client credentials flow via Postman like below:

    POST https://login.microsoftonline.com/<tenantID>/oauth2/v2.0/token
    client_id:client_id
    grant_type:client_credentials
    client_secret:client_secret
    scope:https://graph.microsoft.com/.default
    

    Response:

    enter image description here

    When I used the above token to call below query, I got same error:

    POST https://graph.microsoft.com/v1.0/users/signed_in_user_id/changePassword
    {
    "currentPassword": "xxxxxx",
    "newPassword": "xxxxxxxxx"
    }
    

    Response:

    enter image description here

    To resolve the error, you need to use interactive flows like Authorization Code, Username Password etc…

    So, I generated access token using Authorization Code flow via Postman like below:

    POST https://login.microsoftonline.com/<tenantID>/oauth2/v2.0/token
    client_id:client_id
    grant_type:authorization_code
    scope:https://graph.microsoft.com/.default
    client_secret:client_secret
    code:code
    redirect_uri:redirect_uri
    

    enter image description here

    When I used the above token to call below query, password changed successfully like below:

    POST https://graph.microsoft.com/v1.0/users/signed_in_user_id/changePassword
    {
    "currentPassword": "xxxxxx",
    "newPassword": "xxxxxxxxx"
    }
    

    Response:

    enter image description here

    Please note that, /me/changePassword endpoint is same as /users/signed_in_user_id/changePassword endpoint.

    I tried using /me/changePassword endpoint and got same results as below:

    enter image description here

    Code sample in C#:

    GraphServiceClient graphClient = new GraphServiceClient( authProvider );
    var currentPassword = "xxxxxxx";
    var newPassword = "xxxxxxxxxx";
    await graphClient.Me
    .ChangePassword(currentPassword,newPassword)
    .Request()
    .PostAsync();
    

    Reference:
    user: changePassword – Microsoft Graph


    Update:

    https://login.microsoftonline.com/<tenantID>/oauth2/v2.0/authorize?
     client_id=<clientid>
     response_type=code
     redirect_uri=https://jwt.ms
     response_mode=query
     scope=https://graph.microsoft.com/.default
     state=12345
    

    To generate Authorization Code flow, use this above code InPrivate mode and Sign into your account you get a code like this below. For reference

    enter image description here

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search