Microsoft Azure access_token not accepted in CRM requests - azure

I am putting together an api integration with Dynamics CRM on premise (v8.1/8.2), on a IFD, using the password grant type.
I am retrieving an access token successfully, however when I then try to call endpoints (e.g /api/data/v8.2/contacts?$select=fullname,contactid ) I get 401 - access denied errors. When I log into the CRM with the user I can successfully view this data and the error occurs on all tested endpoints.
Interestingly this morning I realised the tokens retrieved cannot be base64 decoded - is that correct?
I could use some ideas on what to look at next to resolve the problem. Steps I've taken:
Triple checking the initial token request
Triple checked the Service Root URL
Tried on two CRM/Azure setups
Tried with my own (node) code and internet examples
A wide variety of token setups
Confirmed the user exists in Azure and the CRM
Confirmed user has sufficient permissions
Confirmed the application on Azure has all dynamics permissions granted
Confirmed I am on the same network as Azure and the CRM
It seems apparent that I have a configuration issue somewhere in Azure or the CRM. However no guide or question I can find suggests looking at problems I haven't already checked for and I could really use some input from those who have had to make adjustments in obscure settings ect.
Heres my token request:
var options = {
method: 'POST',
url: 'https://login.microsoftonline.com/<snip>/oauth2/token', //for 'intercity technology' (guid is unique)
headers:
{
'cache-control': 'no-cache',
'content-type': 'multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW' },
formData:
{
grant_type: 'password',
client_id: ‘<snip>’, //aplication id
client_secret: ‘<snip>’, //any key in the keys list
username: ‘<snip>’,
password: ‘<snip>’, // and their password
resource: ‘<snip>’ //application id
}
};
logger.debug(util.inspect(options));
request(options, function (error, response, body) {
...
Heres my current api request test:
var options = {
method: 'GET',
url: organisation_url + '/api/data/v8.2/contacts?$select=fullname,contactid',
headers: {
Authorization: 'Bearer '+token,
Accept: 'application/json',
'OData-MaxVersion':4.0,
'OData-Version': 4.0,
'Content-Type': 'application/json; charset=utf-8',
'Prefer': 'odata.maxpagesize=500',
'Prefer': 'odata.include-annotations=OData.Community.Display.V1.FormattedValue'
}
};
logger.debug(util.inspect(options));
request(options, function (error, response, body) {
...

You'll need to use a grant type of 'client_credentials' instead of 'password' as the later isn't supported.
Something like:
grant_type: 'client_credentials',
client_id: ‘<snip>’, //aplication id
client_secret: ‘<snip>’, //any key in the keys list
resource: ‘<snip>’ //CRM Url
Follow the guide here and all the links to ensure the AAD application is registered correctly and the CRM application user is in place.

Related

Azure B2C login with Cypress using cy.request()

Our app requires Azure b2c authentication when login in. I automated the login by simply typing the username and password. In addition I had to add "chromeWebSecurity": false to avoid cross-origin issue.
I think this is the incorrect way of login in. While I was searching for a solution I came across some articles regarding this. Apparently we could user Cy.request() and get the response and then access the app.
However, I was unable to implement this.
Has anyone implemented the Azure b2c login automation with cypress ? if so can someone explain how this needs to be done ?
Our app uses access bearer tokens.
It first sends authentication requests
GET https://{tenant}.b2clogin.com/{tenant}.onmicrosoft.com/oauth2/v2.0/authorize
Then gets the token
POST https://{tenant}.b2clogin.com/{tenant}.onmicrosoft.com/oauth2/v2.0/token
Thanks
I'm not too familiar with Azure b2c authentication, but looks like the general pattern is given here How to use Cypress to test your SharePoint solution with an Azure AD-secured API
The bulk of the code is this
Cypress.Commands.add("visitWithAdal", (pageUrl) => {
const config = {
username: process.env.CI ? Cypress.env('USERNAME') : Cypress.env('username'),
password: process.env.CI ? Cypress.env('PASSWORD') : Cypress.env('password'),
tenant: process.env.CI ? Cypress.env('TENANT') : Cypress.env('tenant'),
clientId: process.env.CI ? Cypress.env('CLIENTID') : Cypress.env('clientid'),
clientSecret: process.env.CI ? Cypress.env('CLIENTSECRET') : Cypress.env('clientsecret'),
resource: process.env.CI ? Cypress.env('RESOURCE') : Cypress.env('resource')
};
// Fetch the access token for the Microsoft Graph
cy.request({
method: 'POST',
url: `https://login.microsoft.com/${config.tenant}/oauth2/token`,
header: {
'cache-control': 'no-cache',
'Content-Type': 'application/x-www-form-urlencoded'
},
form: true,
body: {
grant_type: 'password',
client_id: config.clientId,
client_secret: config.clientSecret,
resource: config.resource,
password: config.password,
username: config.username
}
}).then(response => {
if (response && response.status === 200 && response.body) {
const accessToken = response.body["access_token"];
const expires = response.body["expires_on"];
// Store the retrieved access token in the session storage
cy.window().then((crntWindow) => {
crntWindow.sessionStorage.setItem(`adal.token.keys`, `${config.resource}|`);
crntWindow.sessionStorage.setItem(`adal.expiration.key${config.resource}`, expires);
crntWindow.sessionStorage.setItem(`adal.access.token.key${config.resource}`, accessToken);
cy.visit(pageUrl);
});
}
});
});

Getting error on using refreshToken for googleAPI to get new access token

My code to get the access token using a refresh token was working fine, but suddenly has stopped working and I'm getting exception as
unauthorized client and status code as 401.
Below is my sample code:
request({
method: 'POST',
headers: {
'Content-type': 'application/x-www-form-urlencoded'
},
data: {
client_id: XXXXX,
client_secret: XXXXX,
refresh_token: myRefresh_Token_Here,
grant_type: 'refresh_token'
},
URL: "https://oauth2.googleapis.com/token"
})
.then(response => {
resolve(response);
})
.catch(exception => {
reject(exception);
});
Below is the error what i get
this i get in below object
exception.response.data
{"error":"unauthorized_client","error_description":"Unauthorized"}'
No other info, also the status code is 401
unauthorized client
Normally means that the client id and client secret you are using to pair with a refresh token is not the pair that was used to create the refresh token in the first place.
I would double check you have the correct client id and client secret or that someone didn't regenerate your secret on Google cloud console.

status 401 Unauthorized Auth0 access token Node JS Heroku

So I'm trying to get an access token in order to delete a user.
var options = {
method: 'POST',
url: 'https://dev-owihjaep.auth0.com/oauth/token',
headers: {'content-type': 'application/json'},
data: {
grant_type: 'client_credentials',
client_id: 'RGPTciPqTAlJSDoO3zkL4GT1HV3fsptj',
client_secret: process.env.AUTH0_CLIENT_SECRET,
audience: 'https://dev-owihjaep.auth0.com/api/v2/'
}
};
let accessTokenResponse = await axios.request(options)
It worked in localhost but for some reason for my deployed app I'm getting status: 401, statusText: 'Unauthorized' and data: { error: 'access_denied', error_description: 'Unauthorized' }. I created client grants for my client, made sure Authorized was switched for my Application in Machine to Machine Applications in Auth0 Management API settings, and made sure Client Credentials was checked for Grant Types for my Application. How I can fix this error?
I had to add my .env environment variable(process.env.AUTH0_CLIENT_SECRET) to my Heroku Config Vars.

Reddit gives 403 when upvoting via API

I've registered as the Web app as required by the Reddit API for the Oauth access with identity, edit, flair, history, modconfig, modflair, modlog, modposts, modwiki, mysubreddits, privatemessages, read, report, save, submit, subscribe, vote, wikiedit, wikiread scopes.
I'd authorized my app and have exchanged the generated code for the access_token with 3600 seconds validity.
'use strict';
let request = require('request');
const USER_AGENT = 'web:com.example.server:v0.0.1 (by /u/sridharrajs)';
const token = '<my access_token within 3600 seconds validity>';
request({
method: 'POST',
url: 'https://www.reddit.com/api/vote',
headers: {
'User-Agent': USER_AGENT,
'Authorization': `bearer ${token}`,
'Content-Type': 'application/x-www-form-urlencoded'
},
form: {
id: "t1_9qy47p",
dir: "1"
},
json: false
}, function (error, response, body) {
if (error) {
console.log('error', error);
} else if (body.error) {
console.log('body.error', body);
}
return console.log(body);
});
But when I try to upvote a reddit submission using API, I get an error.
{"message": "Forbidden", "error": 403}
The link that I'm trying to upvote is Tim Cook warns of ‘data-industrial complex’ in call for comprehensive US privacy laws
I tried switching both bearer and Bearer as per the answer in Reddit API returns HTTP 403, and tried using different User-Agent as suggested in 403 error when trying to get data from Reddit API. Nothing seem to work.
What am I missing?
Solved. I need to use https://oauth.reddit.com instead of www.reddit.com.
You may now make API requests to reddit's servers on behalf of that user, by including the following header in your HTTP requests:
Authorization: bearer TOKEN
API requests with a bearer token should be made to https://oauth.reddit.com, NOT www.reddit.com.

OneDrive Code Flow Public clients can't send a client secret - Node.js

hey guys I want to create access to my onedrive account to upload file via node.js from my home pc windows.
I created a app at https://apps.dev.microsoft.com
Also I created a client secret there and added a web platform and changed the redirect url from localhost to https://login.live.com/oauth20_desktop.srf
Then I used this link in my browser
https://login.live.com/oauth20_authorize.srf?client_id=ab82982b-4dxxxxxxxxxxxxxxxxx&scope=files.readwrite.all&response_type=code
The Url from my browser changed to https://login.live.com/oauth20_desktop.srf?code=M494a5b9fxxxxxxxxxxxxxxxxxxxxxxx&lc=1031
Then I make a POST Request like they told on https://dev.onedrive.com/auth/graph_oauth.htm
with
request({
uri: "https://login.microsoftonline.com/common/oauth2/v2.0/token?"
+ "&client_id=ab82982b-4dbe-4c6b-a1fe-2d60d01709fd&"
+ "client_secret=TkYZhYyuEiSoqhCxbh4Dqh3"
+ "&code=M494a5b9f-5577-3454-a78c-cef649a512c0"
+ "&grant_type=authorization_code",
method: "POST",
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}, function(error, response, body) {
console.log('body: ', body);
});
But the output is
body: {"error":"invalid_request","error_description":"AADSTS90014: The
request body must contain the following parameter: 'grant_type'.\r\nTrace
ID:
de2c2dxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\r\nCorrelation ID:
de2f8b83xxxxxxxxxxxxxxxxxxxxxxxxx\r\nTimestamp: 2017-07-31 13:40:52Z","error_codes":[90014]
,"timestamp":"2017-07-31 13:40:52Z","trace_id":"de2c2da2xxxxxxxxxxxxxxxxxxx","correlation_id":"de2f8b8xxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}
Please help I struggle so hard with this API token stuff ..
EDIT from the comment below I changed too
request.post({url:'https://login.microsoftonline.com/common/oauth2/v2.0/token', form: {
redirect_uri: 'https://login.live.com/oauth20_desktop.srf',
client_id: 'abf3247c-d56a-xxxxxxxxxxxxxxxxxxxxx',
client_secret: '3o6xxxxxxxxxxxxxxxxxxxxxxxxxxxx',
code: 'M8aad1bcf-xxxxxxxxxxxxxxxxxxxxxxxxxx',
grant_type: 'authorization_code'
}
}, function(err,httpResponse,body){ /* ... */
console.log('err: ' + err)
console.log('body: ' + body)
})
But now I get "error":"invalid_request","error_description":"AADSTS90023: Public clients can't send a client secret.
I google this and read that I cant make client secret request with desktop apllications. But I created a web application at https://apps.dev.microsoft.com
Also I delete the client secret from the request I get error that the redirect url is wrong. Please send me working code examples I struggle with this now for several days ..
This is so difficult aaaaaaaaaaaaaaaaaaaaaaahhhhhhhhhhhhh :D Please help
Have your this question been opened yet? It seems that you want to retrieve access token and refresh token. If I misunderstand your question, I'm sorry.
I think that your modified script for retrieving access token is not wrong. Please confirm the authorization flow again.
Add application at https://apps.dev.microsoft.com/
Input Application Name. In this case, don't use Guided Setup
Create Application secret.
Platform is web. In this case, redirect URL is http://localhost
Retrieve code from https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=### Application ID ###&scope=offline_access%20files.readwrite.all&response_type=code&redirect_uri=http://localhost
Please inport above URL to your browser, and retrive the code from redirected URL.
Here, in order to upload files, it includes files.readwrite.all in the scope.
Refresh token can be retrieved by including offline_access to the scope.
Run the following your script to retrieve access token and refresh token.
Script :
request.post({
url:'https://login.microsoftonline.com/common/oauth2/v2.0/token',
form: {
redirect_uri: 'http://localhost',
client_id: 'abf3247c-d56a-xxxxxxxxxxxxxxxxxxxxx',
client_secret: '3o6xxxxxxxxxxxxxxxxxxxxxxxxxxxx',
code: 'M8aad1bcf-xxxxxxxxxxxxxxxxxxxxxxxxxx',
grant_type: 'authorization_code'
}
}, function(err,httpResponse,body){
console.log('body: ' + body)
});
Response :
You can retrieve following response.
{
"token_type": "Bearer",
"scope": "Files.ReadWrite.All",
"expires_in": 3600,
"ext_expi
res_in": 0,
"access_token": "#####",
"refresh_token": "#####"
}
If this is not a solution for you, I'm sorry.
Script for retrieving access token from refresh token :
request.post({
url:'https://login.microsoftonline.com/common/oauth2/v2.0/token',
form: {
redirect_uri: 'http://localhost',
client_id: 'abf3247c-d56a-xxxxxxxxxxxxxxxxxxxxx',
client_secret: '3o6xxxxxxxxxxxxxxxxxxxxxxxxxxxx',
refresh_token: 'xxxxxxxxxxxxxxxxxxxxxxxxxx',
grant_type: 'refresh_token'
}
}, function(err,httpResponse,body){
console.log('body: ' + body)
});

Resources