My goal is to allow users to change and reset their own passwords within my application. We do not want users to be redirected to consent pages.
I've followed the instructions defined here:
But I'm running into the following error:
{
"error": {
"code": "Authorization_RequestDenied",
"message": "Insufficient privileges to complete the operation.",
"innerError": {
"request-id": "19c43c69-f553-470e-9432-617395f5f8f5",
"date": "2017-06-01T17:24:11"
}
}
}
My patch request:
PATCH /v1.0/users/2b6c3114-d81b-429d-af7e-c822a456ebba HTTP/1.1
Host: graph.microsoft.com
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJ...xnsYVw
Content-Type: application/json
Cache-Control: no-cache
Postman-Token: 73f...d6
{
"passwordProfile": {
"password": "w",
"forceChangePasswordNextSignIn": false
}
}
Here's my graph permissions:
Delegated permissions:
User.Read
, User.ReadWrite
, Directory.AccessAsUser.All
*, Directory.ReadWrite.All
*, User.ReadWrite.All
*
Application Permissions:
Directory.ReadWriteAll
*, User.Read.All
*, User.ReadWrite.All
*
* Admin Consent Required
I understand that the scope Directory.AccessAsUser.All
is required when using the passwordProfile
property. Since this isn't available as an application permission, does this mean I have to get access on behalf of a user and use the Authorization Code grant? I don't see any possible way to avoid user consent when using authorization codes to retrieve a token.
EDIT 1
I've tried getting the token using the client_credentials grant_type but I always receive a message that the scope is invalid if I don't use a scope of https://graph.microsoft.com/.default
:
POST /tenantid/oauth2/v2.0/token HTTP/1.1
Host: login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded
Cache-Control: no-cache
Postman-Token: 006...85
client_id={id}&scope=https://graph.microsoft.com/User.Read&client_secret={secret}&grant_type=client_credentials
So I will caveat this answer with the fact that there may be good reasons for doing what you are doing, but you should be aware of all the things that the organization will lose by bypassing Azure AD sign-in and related features like SSPR. Please see this excellent blog post that describes some of the things you'll lose - plus while this is still relevant, there are now MORE security features that your customer will lose, like conditional access.
Anyways, assuming you want to press ahead...
For your scenario (an app service that bypasses Azure AD SSPR and change password experiences), there is an option for change password (that it appears we did not document - filing a bug for that) and regrettably nothing I can offer for password reset. Let me address the first one.
Change Password - in Microsoft Graph (although not documented) you'll find the "changePassword" method on user - ../users/{id}/changePassword, which takes the old password and a new password. This API works ONLY for the signed-in user (so it requires the delegated OAuth2 code flow). It requires an admin to consent for Directory.AccessAsUser.All (although we are looking at adding a more granular permission).
Reset password - there is no app-only permission exposed by Microsoft Graph for this. This is an extremely powerful permission to grant to an application. You've already been given the workaround by support, for an admin to explicitly grant this using powershell. This grants your app a lot of privileges to your customer's resources. Alternatively, there is a delegated permission (Directory.AccessAsUser.All) that allows an admin user to reset another user's password. However this wouldn't be a self-service experience.
Hope this helps,
I have resolved this after talking to Microsoft.
Turns out that app registrations need a role assigned to them.
- Install the Azure AD Module -
https://docs.microsoft.com/en-us/powershell/msonline/
- Open a
“Microsoft Azure Active Directory Module for Windows PowerShell”
command prompt:
$AADCreds = Get-Credential // You will be prompted for your credentials
Import-Module MSOnline Connect-MsolService -Credential $AADCreds Get-MsolServicePrincipal -AppPrincipalId "" // Note: Copy the ObjectId for your Service Principal
Add-MsolRoleMember -RoleName "" -RoleMemberObjectId -RoleMemberType ServicePrincipal
I used "User Account Administrator" for the directory role.