I'm trying to change an Azure AD user password.
The user is already authenticated in a SPA application using the implicit flow and the adal
library.
While calling:
return await graphClient.Me.Request().UpdateAsync(new User
{
PasswordProfile = new PasswordProfile
{
Password = userPasswordModel.NewPassword,
ForceChangePasswordNextSignIn = false
},
});
I'm getting this exception:
{"Code: Request_ResourceNotFound\r\nMessage: Resource '35239a3d-67e3-4560-920a-2e9ce027aeab' does not exist or one of its queried reference-property objects are not present.\r\n\r\nInner error\r\n"}
Debugging the access token I got with Microsoft Client SDK
I see that this GUID is referring to the oid
and sub
properties. See below:
This is the code I use to acquire the token:
IConfidentialClientApplication clientApp =
ConfidentialClientApplicationBuilder.Create(Startup.clientId)
.WithAuthority(string.Format(AuthorityFormat, Startup.tenant))
.WithRedirectUri(Startup.redirectUri)
.WithClientSecret(Startup.clientSecret)
.Build();
var authResult = await clientApp.AcquireTokenForClient(new[] { MSGraphScope }).ExecuteAsync();
return authResult.AccessToken;
I'm using the implicit flow in a SPA application. While doing ClaimsPrincipal.Current
I see that my user is authenticated and all claims are present.
I've read a lot of docs @ GitHub and Microsoft Docs but it's still not clear in my mind how to implement this. By the way, I'm using these Microsoft Graph packages:
<package id="Microsoft.Graph" version="1.15.0" targetFramework="net461" />
<package id="Microsoft.Graph.Auth" version="0.1.0-preview.2" targetFramework="net461" />
<package id="Microsoft.Graph.Core" version="1.15.0" targetFramework="net461" />
I guess I'm not approaching this correclty because instead of acquiring a token for the application I should acquire a token for the user. Should I use clientApp.AcquireTokenOnBehalfOf
instead?
If so what's the recommended way of acquiring a token for the currently logged in user using Microsoft Graph API SDK?
Can you shed some light?
####### EDIT #######
I was able to make some progress using this:
var bearerToken = ClaimsPrincipal.Current.Identities.First().BootstrapContext as string;
JwtSecurityToken jwtToken = new JwtSecurityToken(bearerToken);
var userAssertion = new UserAssertion(jwtToken.RawData, "urn:ietf:params:oauth:grant-type:jwt-bearer");
IEnumerable<string> requestedScopes = jwtToken.Audiences.Select(a => $"{a}/.default");
var authResult = clientApp.AcquireTokenOnBehalfOf(new[] { MSGraphScope }, userAssertion).ExecuteAsync().GetAwaiter().GetResult();
return authResult.AccessToken;
but now I'm getting the error:
insufficient privileges to complete the operation. authorization_requestdenied
Roles
rather thanscp
. Roles are Applications copes (Client Credentials) which implies you're not using Implicit here. What you want is Implicit using theDirectory.AccessAsUser.All
scope. – Keltonroles
) cannot be used to reset user passwords. Only Delegated scopes support resetting passwords. This ensures that any password reset can be audited back to a specific user ("a throat to choke" as they say). – KeltonclientApp.AcquireTokenForClient
instead ofclientApp.AcquireTokenOnBehalfOf
. Posted an answer below. – Commence