Change Azure B2C account password on behalf of a user - azure

I'm trying to change the password of a user created in my Azure B2C Tenant. I'm using Microsoft.Graph C# SDK to do API calls.
First I create GraphServiceClient by providing details of my tenant:
var options = new TokenCredentialOptions
{
AuthorityHost = AzureAuthorityHosts.AzurePublicCloud
};
var clientSecretCredential = new ClientSecretCredential("tenantId", "clientId", "clientSecret", options);
_client = new GraphServiceClient(clientSecretCredential);
Then I use the built-in method of a client to change the user's password:
await _client.Users["userId"].ChangePassword(currentPassword, newPassword).Request().PostAsync();
But I get following error:
Microsoft.Graph.ServiceException: Code: Authorization_RequestDenied
Message: Access to change password operation is denied.
Is it possible to change the password on behalf of a user? I found conflicting information on this topic on the internet. If this is impossible, what is the valid approach to do this?
I have a SPA frontend app in which the user is authenticated with redirection flow. The access token is then passed to my backend to authorize the requests. Maybe I can use this token to somehow access MS Graph API and change the password?
Note: I would like to let users change their passwords without leaving my SPA application.

I tried in my environment and got below results:
Initially I tried with your code and got same error:
According to MS-DOCS change password we need Directory.AccessAsUser.All permission and it only supported for delegated (Work or school accounts).
Trying to reset the password in the B2C tenant using the Graph API its is not possible Unfortunately, because there is no Directory.AccessAsUser.All, B2C tenant does not allow this type of password reset. For B2C tenants, the Graph API includes the permission. Only offline access and openID are available as delegated rights in the B2C tenant.
You can reset the password in B2C tenant are either admin performing password reset via Azure Portal or by using Password Reset Policy and also refer this MS-Q&A for updating password in powershell and postman.
Reference:
"Upn from claims with value null is not a valid upn." - Microsoft Q&A by amanpreetsingh-msft.

Related

Access token retrieved from Azure using OAuth2 does not contain permission

I am working on a solution that needs to retreive email from a mailbox from a tenant using MS Graph API.
The solution needs to run in the background, with no use input (eg call login page for email in browser)
I have registered an Azure application, and have Admin consent for the MS Graph API:
Api permissions
My VB code is as follows (client_id, client_secret, tenant has been removed as confidential):
Dim http As New Chilkat.Http
Dim req As New Chilkat.HttpRequest
Dim json As New Chilkat.JsonObject
' Use the application ID for the client_id.
' (In Azure App Registrations, use the Application (client) ID)
req.AddParam(client_id, )
req.AddParam(client_secret, )
req.AddParam(tenant, )
req.AddParam(scope, https://graph.microsoft.com/.default)
'req.AddParam(username, )
'req.AddParam(password, )
req.AddParam(grant_type, client_credentials)
Dim resp As Chilkat.HttpResponse
' Replace {tenant} with your tenant ID, such as 112d7ed6-71bf-4eba-a866-738364321bfc.
resp = http.PostUrlEncoded(https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token, req)
If (http.LastMethodSuccess True) Then
Debug.WriteLine(http.LastErrorText)
Exit Sub
End If
Dim statusCode As Integer = resp.StatusCode
Debug.WriteLine(response status code: statusCode)
Debug.WriteLine(response body:)
Debug.WriteLine(resp.BodyStr)
I can see the above connecting to the Azure app. However, no permission (scope) is returned in the access token.
When I connect to MS Graph via browser, the token has all the required scope.
Can you please help/advise why I am unable to retreive token with permissions from the MS Graph API in vb?
Please note that, you cannot get scp claim in the token, as
user is not involved in generating token from client_credentials
grant type.
I assigned the same API permissions to my application like below:
When I decoded the access token(generated using client credentials grant type), scp claim is not present in the token like below:
You have to use authorization code flow grant type to get
scp claim in the decoded token, where user interaction is involved.
When I decoded the access token generated using authorization code flow, got scp claim successfully in the token like below:
To know more about authorization code flow, please refer below link:
Microsoft identity platform and OAuth 2.0 authorization code flow - Microsoft Entra | Microsoft Docs
You are using a client_credentials flow, which is an app-only context authentication.
The scp claim is only for user based authentication.
If you want to use the client_credentials flow, you will need to grant Application permissions on your app registration, instead of Delegated.
These applications permissions will then be present inside a roles claim. You can check the description of these claims here:
https://learn.microsoft.com/en-us/azure/active-directory/develop/access-tokens

Updating federated user's adb2c UserPrincipalName via Graph API

We are allowing External Azure AD users to signup and login to our application via a custom policy. This creates a shell user in our azure ad org and we use the user's email address under user profile, not the user's UPN from the external AD. If the user's email address is different from their UPN, the shell user in our adb2c org will have the email address as the UPN. We customized the custom policy to return the user attributes from the external AD together with the user attributes from the shell user in adb2c. Our application will detect if there is a change in the name or email address and will update adb2c shell user via Microsoft Graph.
When the user's email address changes, I want to update the shell user in our adb2c org. Since the email address is used as the UPN, how can I update my federated users userPrincipalName in our adb2c shell user via Graph API?
var identities = graphUser.Identities.Select(o => new ObjectIdentity
{
SignInType = o.SignInType,
Issuer = o.Issuer,
IssuerAssignedId = o.IssuerAssignedId,
ODataType = o.ODataType,
AdditionalData = o.AdditionalData
}).ToList();
var federatedIdentity = identities.FirstOrDefault(i => i.SignInType == "federated");
Both of these wont work:
federatedIdentity.IssuerAssignedId = "mynameuser#federatedAAD.org";
or
var updatedUser = new User
{
//other user attributes here
UserPrincipalName = "mynameuser#federatedAAD.org";
};
await _graphServiceClient.Users[idpId]
.Request()
.UpdateAsync(updatedUser);
Thanks in advance!
• You can update the external user identity or shell user identity in Azure AD B2C using Microsoft graph API through the HTTP response interface by using the below commands: -
‘ PATCH https://graph.microsoft.com/v1.0/users/{object id}
{"userPrincipalName":"jdoe#abc.com"} ‘
Where instead of the “jdoe#abc.com”, enter the user principal name of the already created Azure AD B2C shell user or federated user that logs in to Azure AD B2C. Since, the user identity is already created when the user logs in for the first time to use the application created, it needs to update the existing user principal name only which can be done through the above command.
• Also, Microsoft Graph seems not to allow to set userPrincipalName when creating the user for Azure B2C. It will generate the userPrincipalName as {object id}#abc.com. And then you could update the userPrincipalName. Thus, your second command script to create or update the shell user’s UPN didn’t work. As well as ensure to add the federated domain as a verified domain in Azure AD B2C for the above command and options to succeed.
Please refer the below links for more information: -
Pre-Create Federated Users in Azure B2C Using Graph
https://learn.microsoft.com/en-us/graph/api/user-update?view=graph-rest-1.0&tabs=http

How login into AAD with ADAL and MFA

I am trying to create a nodejs api, that connects to to Azure Active directory using the ADAL plugin (https://github.com/AzureAD/azure-activedirectory-library-for-nodejs).
All works ok for normal users, but if a user has MFA (Multi-Factor Authentification) enabled, it fails and throws and error message.
I found this related to ADAL-MFA: https://github.com/AzureAD/azure-activedirectory-library-for-nodejs/issues/151 but it's not clear for me from his answer if it's possible or not, and how to implement MFA.
The plugin has very poor documentation and it's not clear for me how I can retrieve the error message and vars from it. It's says that the error var is a object but it's a string.
Here is my code from the endpoint which works for normal users:
var adal = require('adal-node');
var AuthenticationContext = adal.AuthenticationContext;
var authorityUrl = parameters.authorityHostUrl + '/' + parameters.tenant;
var resource = '00000003-0000-0000-c000-000000000000';
var context = new AuthenticationContext(authorityUrl, true, new adal.MemoryCache);
context.acquireTokenWithUsernamePassword(resource, parameters.username, parameters.password, parameters.clientId, function(err, token) {
if(err){
mysql_connection.end();
return callback(null, {
status: false,
error: err.stack,
log: logging.message,
test: 1
});
}
)};
So basically I need to use user credentials (e-mail and password) to connect to AAD api, but server to server (my nodeJS api to AAD api). And it needs to work with MFA.
(web app -> nodeJS API -> AAD API)
acquireTokenWithUsernamePassword worked perfectly for this, but it does not work with MFA, or I don't know to make the correct adjustments to make it work.
You are using Resource Owner Password Credentials Grant flow (ROPC), and hit one of the exact scenarios why I tell people not to use it. (except maybe for test automation)
You can't use ROPC with users that have MFA. Neither can you use it with users who are federated from on-prem AD or Microsoft personal accounts. Or with users whose password has expired and needs to be reset.
You need to switch your API to acquire the token using either On-behalf-of grant flow (exchanges the access token your API got for a new token, continuing the delegation) or client credentials flow (acquire token with app credentials alone, no user context).
On-behalf-of flow

Error when obtaining token

I'm trying the sample code NativeClient-Headless-DotNet.sln against my B2C tenant.
When I attempt to execute the command:
result = authContext.AcquireTokenAsync(todoListResourceId, clientId, uc).Result;
using an existing username and password, I get this exception:
InnerException = {"unknown_user_type: Unknown User Type"}
As far as I know, I've set-up all the values correctly in Web and App config (I'm using the same values that I use in my Graph API project, which works OK).
Any ideas why this should happen?
Are accounts created with:
userType.type = "userName";
found by this method?
Currently, Azure AD B2C doesn't have any direct support for this.
However, work to support for the Resource Owner Password Credentials flow in Azure AD B2C is in-progress.
This new feature will enable a desktop application to collect a user credential and POST it to the B2C tenant for validation.

Azure AD OpenIDConnect + ASP.NET Core - Authenticate and Extra Permissions/Token?

I am using the following bits against my Azure AD to authenticate with ASP.NET Core.
https://azure.microsoft.com/en-us/resources/samples/active-directory-dotnet-webapp-openidconnect-aspnetcore/
https://github.com/Azure-Samples/active-directory-dotnet-webapp-openidconnect-aspnetcore
I have the basic login/auth working after creating an Azure AD app. User can login/logout.
My question is given this, what's the best way when a user Auth's to log to a DB? I thought about making the redirect URL to an endpoint, saving, then just redirecting back to "Home" but is that ideal?
Also, is it possible to retrieve a bearer token via this approach? Or does this require another type of call or extending "scope"? So that for example I could retrieve the authenticated users Manager.
https://graph.microsoft.com/v1.0/me/manager
My question is given this, what's the best way when a user Auth's to log to a DB? I thought about making the redirect URL to an endpoint, saving, then just redirecting back to "Home" but is that ideal?
This way only able to log those who already sign-in your app successfully. It is not able to log those users who are attempt to sign-in your app but enter the wrong password.
Azure AD already provide lots of report to gain visibility into the integrity and security of your organization’s directory.( refer here)
And if you are using the Azure AD Premium, you can review the sign-in activities via the Azure new portal below:
And if you want to store the sign-in activity in your web app, you can write the custom code after the token is verified. Here is the code for your reference:
// Configure the OWIN pipeline to use OpenID Connect auth.
app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions
{
ClientId = Configuration["AzureAD:ClientId"],
Authority = String.Format(Configuration["AzureAd:AadInstance"], Configuration["AzureAd:Tenant"]),
ResponseType = OpenIdConnectResponseType.IdToken,
PostLogoutRedirectUri = Configuration["AzureAd:PostLogoutRedirectUri"],
Events = new OpenIdConnectEvents
{
OnRemoteFailure = OnAuthenticationFailed,
OnTokenValidated = context => {
//write the custom code to store users login-in
return Task.FromResult(0); }
},
});
Also, is it possible to retrieve a bearer token via this approach?
Yes. We can get the token after receive the authorization code. You can refer the code sample here to acquire the token from asp.net core app.

Resources