How login into AAD with ADAL and MFA - node.js

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

Related

Change Azure B2C account password on behalf of a user

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.

Getting AAD App access token to call Azure App service with client secret

I am writing a Nodejs CLI to Deploy AAD-Auth Protected Web API via Azure ARM template. Facing issues in getting Access-Token to invoke the Web API.
I have used adal-node library to generate access token using AAD-App clientID and secret, but the generated token doesn't have valid objectId.
I also tried to get device_code and then tried to acquire access-token with same, but failed with error "needs permission to access resources in your organization that only an admin can grant. Please ask an admin to grant permission to this app before you can use it."..
However, if I go to the browser and enter https://app-service-name.azurewebsites.net/.auth/me, i am prompted to enter my azure login credentials and consent to let AAD-App access the resources, I am getting Access-token on the browser. And this access-token has all the properties (audience, issuer, objectId) i need. I am struggling to acquire similar access-token from nodejs CLI.
const context = new AuthenticationContext('https://login.microsoftonline.com/my-tenant-id');
context.acquireTokenWithClientCredentials(
aadAppIdUri, aadAppId, aadClientSecret, (err: Error, result: any) => {
if (err) {
reject(err);
} else {
resolve(result.accessToken);
}
});
I want to invoke the AAD-Protected web api from my Node CLI with valid Access-Token. Kindly help me generate the Access-Token for this.
The way you get the access token via client credentials need application permission.
The way you get the access token via login credentials need delegated permission.
Make sure you have the needed application permission for your app.
Also, remember to click grant admin consent button.

ADAL failed to return token in webAPI. Error:Invalid jwt token using userassersion

A native app created which is calling web api.Two apps has been created in the azure.Here is the code code for getting access token and it worked well,I am getting access token:
UserCredential uc = new UserPasswordCredential(userName, password);
result = authContext.AcquireTokenAsync(todoListResourceId,clientId,
uc).Result;
Now to access new token after the expiry of old one(1 hr) i am using the code:
AuthenticationContext authContext = new AuthenticationContext(authority);
UserAssertion userAssertion = new UserAssertion(oldToken, "urn:ietf:params:oauth:grant-type:jwt-bearer", userName);
AuthenticationResult result = authContext.AcquireTokenAsync(todoListResourceId, clientId, userAssertion).ConfigureAwait(false).GetAwaiter().GetResult();
But I am getting Error as:"Invalid JWT token. AADSTS50027: Invalid JWT token. Token format not valid".
Checked JWT token :it is correct in format can able to decode using jwt.io.
Note: client Id am using for these two code snippet are the same appId.
I know this is the exact duplication of the question asked by devangi.I cannot able to comment on that question that's why I am asking it again.
Any one can able to help me out?
Or
It will be great if any one can able to help with other ways to get token with out using user password since i need to internally generate new token without user enter password again.
For the scenario when user has authenticated on a native application, and this native application needs to call a web API. Azure AD issues a JWT access token to call the web API. If the web API needs to call another downstream web API, it can use the on-behalf-of flow to delegate the user’s identity and authenticate to the second-tier web API .
Please refer to this document for more details about On-Behalf-Of flow . You can also refer to code sample .
For the scenario when when a daemon application(Your web api) needs to call a web API without user's identity , you should use client credential flow to use its own credentials instead of impersonating a user, to authenticate when calling another web service. Code sample here is for your reference .
Please click here for explanation about above two scenarios. Your code is using Resource Owner Password Credentials Grant ,this flow has multi restrictions such as don't support 2FA and is not recommended .
If i misunderstand your requirement , please feel free to let me know .

Authenticate to Azure AD on-behalf-of a client application

In a scenario like this: https://github.com/Azure-Samples/active-directory-dotnet-webapi-onbehalfof
I want to authenticate to Azure AD in the back end on behalf of a client instead of a user. I couldn't find an appropriate example in the documentation that fits this case.
So what am I doing?
In the client:
var authContext = new AuthenticationContext(authorityUrl);
var result = authContext.AcquireTokenAsync(webServiceUri, new ClientCredential(nativeClientId, nativeClientSecret)).GetAwaiter().GetResult();
In the back end service:
var authContext = new AuthenticationContext(authorityUrl);
var result = authContext.AcquireTokenAsync(office365ResourceUri, new ClientAssertion(webClientId, result.AccessToken))
This throws the following exception:
AADSTS70002: Client assertion application identifier doesn't match 'client_id' parameter.
It only succeeds when I'm pointing the same service (refering to itself!) in the back end as from the client:
authContext.AcquireTokenAsync(webServiceUri, new ClientAssertion(nativeClientId, result.AccessToken))
But this doesn't make sense as the service has to go to an Office 365 API.
Anyone an idea?
The OAuth 2.0 On-Behalf-Of flow is to propagate the delegated user identity and permissions through the request chain. For the middle-tier service to make authenticated requests to the downstream service, it needs to secure an access token from Azure Active Directory (Azure AD), on behalf of the user.
In your scenario , you could use client credential flow to acquire token for the office 365 api in your service app , without any human interaction such as an interactive sign-on dialog .
Please click here for more details about Authentication Scenarios for Azure AD .

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