I have a Nodejs app that uses adal-node and dynamics-web-api (https://www.npmjs.com/package/dynamics-web-api) to query our Dynamics 365 instance.
I'm trying to migrate from ADAL to MSAL, roughly following these guidelines: https://learn.microsoft.com/en-us/azure/active-directory/develop/msal-node-migration
Old code using ADAL does this to obtain an access token - it's been working fine:
var DynamicsWebApi = require('dynamics-web-api');
var clientId = '[My Azure registered apps client ID]';
var AuthenticationContext = require('adal-node').AuthenticationContext;
//OAuth Token Endpoint
var authorityUrl = 'https://login.microsoftonline.com/[Azure tenant ID]/oauth2/token';
//CRM Organization URL
var resource = 'https://[my domain].crm.dynamics.com/';
var username = '[DYNAMICS_USERNAME]';
var password = '[DYNAMICS_PASSWORD]';
var adalContext = new AuthenticationContext(authorityUrl);
var accessToken='';
//add a callback as a parameter for your function
function acquireToken(dynamicsWebApiCallback){
//a callback for adal-node
function adalCallback(error, token) {
if (!error){
//call DynamicsWebApi callback only when a token has been retrieved
accessToken=token.accessToken;
dynamicsWebApiCallback(accessToken);
// pass back the access token
callback(null,accessToken);
}
else{
console.log('Token has not been retrieved. Error: ' + error.stack);
callback(error,null);
}
}
//call a necessary function in adal-node object to get a token
adalContext.acquireTokenWithUsernamePassword(resource, username, password, clientId, adalCallback);
}
var dynamicsWebApi = new DynamicsWebApi({
webApiUrl: 'https://[my domain].api.crm.dynamics.com/api/data/v9.0/',
onTokenRefresh: acquireToken
});
//call any function
dynamicsWebApi.executeUnboundFunction("WhoAmI").then(function (response) {
callback(null,accessToken);
}).catch(function(error){
callback(error,null);
});
/*************************************************************************************************/
Below is new code using MSAL. The call to acquireTokenByUsernamePassword() correctly returns a token, but when I attempt to use the accessToken in subsequent calls
to query Dynamics via the DynamicsWebApi API, I get 401 Unauthorize errors.
- I've added the API permissions for Dynamics CRM / Dataverse to the app in Azure - you can see that in the scopes
- The account I'm using has the necessary privileges - same account works fine in the ADAL solution above
- not sure what I'm missing var DynamicsWebApi = require('dynamics-web-api');
var msal = require("@azure/msal-node");
var accessTemp = ''; const clientConfig = {
auth: {
clientId: '[My Azure registered apps client ID]',
authority: 'https://login.microsoftonline.com/[tenant ID]',
}
}; const pca = new msal.PublicClientApplication(clientConfig); const usernamePasswordRequest = {
scopes: [ 'https://admin.services.crm.dynamics.com/user_impersonation',
'https://graph.microsoft.com/User.Read'],
username: '[DYNAMICS_USERNAME]',
password: '[DYNAMICS_PASSWORD]',
}; //add a callback as a parameter for your function
function acquireToken(dynamicsWebApiCallback){
pca.acquireTokenByUsernamePassword(usernamePasswordRequest)
.then(response => {
accessToken = response.accessToken;
dynamicsWebApiCallback(accessToken);
callback(null,accessToken);
})
.catch(error => {
console.error('Token has not been retrieved. Error: ' + error.stack);
callback(error,null);
});
} var dynamicsWebApi = new DynamicsWebApi({
webApiUrl: 'https://[my domain].api.crm.dynamics.com/api/data/v9.0/',
onTokenRefresh: acquireToken
}); //call any function
dynamicsWebApi.executeUnboundFunction("WhoAmI").then(function (response) {
console.log('executed whoami:', response);
callback(null,accessToken);
}).catch(function(error){
callback(error,null);
}); /*************************************************************************************************/ 401 Unauthorized error details:
"status_code": 200,
"content_type": "application/json",
"parsed": {
"message": "Unexpected Error",
"status": 401,
"statusMessage": "Unauthorized",
"headers": {
"allow": "OPTIONS,GET,HEAD,POST",
"x-ms-service-request-id": "2de8402d-b5da-493d-b190-xxxxxxxxxxxx, f818649e-cce3-49d8-bd91-xxxxxxxxxxxx",
"set-cookie": [
"ARRAffinity=838ff9bc421a5390cb60466a3e7023695ec37110a091f2b71999xxxxxxxxxxxx; domain=xxxxxxxxxxx.api.crm.dynamics.com; path=/; secure; HttpOnly"
],
"www-authenticate": "Bearer authorization_uri=https://login.microsoftonline.com/[xxxxxxxxxxx]/oauth2/authorize, resource_id=https://xxxxxxxx.api.crm.dynamics.com/",
"strict-transport-security": "max-age=31536000; includeSubDomains",
"req_id": "f818649e-cce3-49d8-bd91-xxxxxxxxxxxx",
"authactivityid": "d72a04dd-0f6c-48b2-9747-xxxxxxxxxxxx",
"nativewebsession-version": "2",
"x-source": "170824215124150113103417514167243873422349142230147229211401501981611161241xxxxxxxxxxxx, 88422011721969210810713227100195981721461771441015125146249147142152211xxxxxxxxxxxx",
"public": "OPTIONS,GET,HEAD,POST",
"date": "Wed, 26 Jan 2022 23:37:07 GMT",
"content-length": "0"
}
Any assistance would be appreciated!
Thanks,
Rob Taylor