I'm trying to get the access token for my Microsoft-Graph application using request to send a POST request.
The problem is that the token i get as a response is only 1188 characters long. While the token i get when i use Postman is 1461 characters long. Every time i send a request it generates a brand new token, but the one i get through request in nodejs is always 1188 and the one in postman is always 1461.
I have tried different things such as generating a new app api id in Microsoft Azure, but it keeps giving the same results.
This is my code, i took out sensitive information though by replacing it with the word CENSORED.
I'm using the EXACT same request parameters in Postman
const endpoint = "https://login.microsoftonline.com/CENSORED/oauth2/token";
const requestParams = {
client_id: "CENSORED",
client_secret: "CENSORED",
resource: "https://graph.windows.net",
grant_type: "client_credentials"
};
let accessToken = await
request.post({
url: endpoint,
form: requestParams
}, function (err, response, body) {
if (err) {
console.log("error");
} else {
console.log("Body=" + body);
let parsedBody = JSON.parse(body);
if (parsedBody.error_description) {
console.log("Error=" + parsedBody.error_description);
} else {
getCalendarEvents(parsedBody.access_token);
}
}
});
Postman returns an 1461 characters long access token and nodejs request only returns a 1188 characters long access token.
This is what i'm using in Nodejs: https://www.npmjs.com/package/request
The resource https://graph.windows.net is for the legacy Azure AD Graph API. This is a completely separate API from the Microsoft Graph. For the Microsoft Graph, the resource should be https://graph.microsoft.com:
const endpoint = "https://login.microsoftonline.com/{tenant}/oauth2/token";
const requestParams = {
client_id: "{clientid}",
client_secret: "{clientsecret}",
resource: "https://graph.microsoft.com",
grant_type: "client_credentials"
};
Apparently the resource parameter should be https://graph.microsoft.com instead of https://graph.windows.net.
Related
I am having problems getting the correct token for triggering my cloud function.
When testing through POSTMAN I get the token by running the following command:
gcloud auth print-identity-token
and my functions works correctly.
But on my server I am using the following code. I also do see the token but I get 401 with this token.
// Constants------------
const metadataServerTokenURL = 'http://metadata/computeMetadata/v1/instance/service-accounts/default/identity?audience=';
async function gToken(){
let token='';
try{
// Fetch the token
const tokenResponse = await fetch(metadataServerTokenURL + 'https://'+process.env.CLOUD_URL, { //URL WITHOUT THE PATH
headers: {
'Metadata-Flavor': 'Google',
},
});
token = await tokenResponse.text();
} catch (err){
console.log(err);
}
return token;
}
---------EDIT-------
The calling function::
app.get("/", async function(req , res){
try {
const token = await getToken();
console.log(`Token: ${token}`);
const functionResponse = await fetch('https://'+process.env.CLOUD_URL+process.env.PATH_TO_FUNC, {
method: 'post',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${token}`},
});
console.log(`Status: ${await functionResponse.status}`);
res.sendStatus(200);
} catch (err){
console.log(err);
res.status(400).send('Something went wrong')
}
})
My server is my NodeJS code running on AppEngine.
What am I doing wrong please?
----------EDIT 2--------------
I entered the two tokens received using two different ways, they show different information for some reason. Please see below::
Token from the server
Token using gcloud command locally (which works)::
Server code and cloud functions are both hosted in the same region, and are a part of the same project.
process.env.CLOUD_URL > "e****-***2-c******-e******2.cloudfunctions.net"
What #Charles and #John mentioned in the comment is correct. You should include the name of the receiving function in the audience:
As mentioned in the docs:
In the calling function, you'll need to create a Google-signed OAuth ID token with the audience (aud) set to the URL of the receiving function.
const metadataServerTokenURL = 'http://metadata/computeMetadata/v1/instance/service-accounts/default/identity?audience=';
...
// Fetch the token
const tokenResponse = await fetch(metadataServerTokenURL + `https://${process.env.CLOUD_URL}/${FUNCTION_NAME}`, {
headers: {
'Metadata-Flavor': 'Google',
}
The audience should look like your HTTP trigger URL. If you decode your JWT ID token, aud looks like this:
{
"aud": "https://[REGION]-[PROJECT_ID].cloudfunctions.net/func-post",
"azp": "117513711437850867551",
"exp": 1614653346,
"iat": 1614649746,
"iss": "https://accounts.google.com",
"sub": "117513711437850867551"
}
I have a Node.js back which currently is running on Firebase in the form of cloud functions. Except for that, I also have an Azure Active Directory with some users that I have invited
So, I want to be able to access them from the Node.js get a list of their emails and names. From what I understood, I can achieve that by making a reference to Microsoft's Graph API and more specifically to their Users API. As every request to Azure AD needs to be OAuth2 authenticated, I was wondering what is the best way of achieving that in my situation. What client flow do I need to implement? I am currently focused on the one which is based on client credentials.
Thanks in advance and whatever general suggestion are more than welcome!
This issue gets Access token and calls Microsoft Graph API using node.js.
The user API of Azure Active Directory Graph API is no longer updating. This MS graph API is newer.
Get access token using client credentials flow:
const request = require("request");
const endpoint = "https://login.microsoftonline.com/[Tenant]/oauth2/v2.0/token";
const requestParams = {
grant_type: "client_credentials",
client_id: "[ApplicationID]",
client_secret: "[Key]",
scope: "https://graph.microsoft.com/.default"
};
request.post({ url:endpoint, form: requestParams }, function (err, response, body) {
if (err) {
console.log("error");
}
else {
console.log("Body=" + body);
let parsedBody = JSON.parse(body);
if (parsedBody.error_description) {
console.log("Error=" + parsedBody.error_description);
}
else {
console.log("Access Token=" + parsedBody.access_token);
}
}
});
Call MS Graph API:
function testListGroupGraphAPI(accessToken) {
request.get({
url:"https://graph.microsoft.com/v1.0/users",
headers: {
"Authorization": "Bearer " + accessToken
}
}, function(err, response, body) {
console.log(body);
});
}
I'm trying to log in using Instagram Basic Display API.
I'm trying to get the access_token, and I'm using axios:
const { code } = queryParams;
const url = `https://instagram.com/oauth/access_token`;
const result = await axios.request({
url,
method: 'POST',
data: {
'client_id': INSTAGRAM_CLIENT_ID,
'client_secret': INSTAGRAM_CLIENT_SECRET,
'grant_type': 'authorization_code',
'redirect_uri': 'https://localhost:3000/auth/instagram/token',
code,
},
});
I'm getting a 400 error, with the message invalid platform app. All the values sent exist and are correct.
My redirect_uri doesn't exist though, but it's added to the authorized URL list. It doesn't exist because I don't have https in my local server.
I had this same issue. The official example given by Instagram using curl uses the -F tag, which means that they are posting the data as the application/x-www-form-urlencoded content-type.
Every other post format I tried is ignored. Changing your code to post as a form and it should work.
There is a very good answer on this post
const querystring = require('querystring');
//Make Object with params const data = {
client_id: 'xxxxxxx',
client_secret: 'xxxxxxxxxxx',
grant_type: 'authorization_code',
redirect_uri: 'https://example.com/auth',
code: 'xxxx' }
//Make the Call
axios.post("https://api.instagram.com/oauth/access_token",
querystring.stringify(data)) .then(function (response) {
console.log("OK", response.data); }) .catch(function (error) {
console.log(error); });
I'd like to use this library to interact with the graph API for my AD - https://github.com/microsoftgraph/microsoft-graph-docs/blob/master/concepts/nodejs.md
However, all of the existing javascript libraries I've found to return access tokens expect a return URL to be passed in, as well as some other web-specific stuff, leading me to believe this is some kind of requirement on Microsoft's end.
Is there any good way to authenticate/receive an access token while running a backend node script (nothing web related) so that I can begin to make calls against the Microsoft Graph API? Thanks in advance for the advice.
BU0's answer didn't work correctly for me because Microsoft changed their way of using the graph API so I wasn't able to get all the data I needed. Here's how I did it using BU0 answer and this tutorial:
const request = require("request");
const endpoint = "https://login.microsoftonline.com/[Tenant]/oauth2/v2.0/token";
const requestParams = {
grant_type: "client_credentials",
client_id: "[ApplicationID]",
client_secret: "[Key]",
scope: "https://graph.microsoft.com/.default"
};
request.post({ url: endpoint, form: requestParams }, function (err, response, body) {
if (err) {
console.log("error");
}
else {
console.log("Body=" + body);
let parsedBody = JSON.parse(body);
if (parsedBody.error_description) {
console.log("Error=" + parsedBody.error_description);
}
else {
console.log("Access Token=" + parsedBody.access_token);
}
}
});
function testGraphAPI(accessToken) {
request.get({
url:"https://graph.microsoft.com/v1.0/users",
headers: {
"Authorization": "Bearer " + accessToken
}
}, function(err, response, body) {
console.log(body);
});
}
To run a back-end non-user-authenticated daemon connected to the Graph API, you want to use the app-only authentication flow. Here's a quick summary of the official steps:
Create your Azure AD Tenant. Note the yourtenant.onmicrosoft.com name, and copy this value down.
Register an application through the global Azure Active Directory blade's App Registrations section, not directly within the tenant properties. Copy the Application ID; we'll need it later.
Create a key tied to the registration and remember to copy it down. Once you click out, you can't get the key value back, so make sure to copy it.
Also update the registration's permissions to what you need, click Save, and then also hit the Grant Permissions button.
Make an HTTP request to the login.microsoftonline.com domain to obtain an access token.
Use the access token to make Graph API requests.
Here's a link to Microsofts Node.js example, and here's a link to the direct documentation on the HTTP call to make to retrieve an access token. And here's a super stripped-down example that will output the retrieved access token. Replace the [Tenant], [ApplicationID], and [Key] values:
const request = require("request");
const endpoint = "https://login.microsoftonline.com/[Tenant].onmicrosoft.com/oauth2/token";
const requestParams = {
grant_type: "client_credentials",
client_id: "[ApplicationID]",
client_secret: "[Key]",
resource: "https://graph.windows.net"
};
request.post({ url:endpoint, form: requestParams }, function (err, response, body) {
if (err) {
console.log("error");
}
else {
console.log("Body=" + body);
let parsedBody = JSON.parse(body);
if (parsedBody.error_description) {
console.log("Error=" + parsedBody.error_description);
}
else {
console.log("Access Token=" + parsedBody.access_token);
}
}
});
Once we have the access_token, we can call out to the Graph API. Assuming the apps permissions were configured correctly and applied from step #4, we can start making Graph API requests:
function testGraphAPI(accessToken) {
request.get({
url:"https://graph.windows.net/[Tenant]/users?api-version=1.6",
headers: {
"Authorization": accessToken
}
}, function(err, response, body) {
console.log(body);
});
}
I had somewhat of an issue for using the url string for the const endpoint
https://login.microsoftonline.com/[Tenant]/oauth2/v2.0/token
Instead, I passed tenant in this way instead from Microsoft graph api docs:
https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize
Reference from docs -> Request an authorization code
Another way:
'use strict';
const axios = require('axios');
const qs = require('qs');
const accessTokenWithCredentials = (tenantId, clientId, clientSecret, resource) => {
const data = {
resource: resource,
grant_type: 'client_credentials',
};
return axios({
url: `https://login.windows.net/${tenantId}/oauth2/token`,
method: "post",
headers: { 'content-type': 'application/x-www-form-urlencoded' },
auth: {
username: clientId,
password: clientSecret,
},
data: qs.stringify(data)
}).catch(error => {
throw error;
})
};
To call the function:
accessTokenWithCredentials(<tenantId>, <clientId>, <clientSecret>, 'https://graph.microsoft.com').then(response => {
console.log(`Got access token`);
const token = JSON.stringify(response.data.access_token);
// do what you need to do
}).catch(err => {
console.log("err " + err);
throw err;
});
I have a problem with my access_token which I get with the serveracceskey. Here is my code in NodeJS:
const admin = require('firebase-admin');
var request = require("request");
const serviceAccount = require('./serverAccountKey.json');
const credential = admin.credential.cert(serviceAccount);
credential.getAccessToken().then((accessTokenInfo) => {
const accessToken = accessTokenInfo.access_token;
const expirationTime = accessTokenInfo.expires_in;
console.log("accessToken " + accessToken );
console.log("expirationTime " +expirationTime);
var s = "Bearer " + accessToken;
request({
headers:{
'Authorization': s
},
uri:"https://firebasedynamiclinks.googleapis.com/v1/SHORTLINK/linkStats?durationDays=7",
method: "GET",
}, function(error, response, body) {
console.log(body);
});
});
and the result is like below:
{
"error": {
"code": 403,
"message": "Request had insufficient authentication scopes.",
"status": "PERMISSION_DENIED"
}
}
What am I doing wrong ? I test the link in Postman too. Something is wrong, I read all the firebase Rest API Doc.
Admin SDK creates tokens with a specific set of scopes: https://github.com/firebase/firebase-admin-node/blob/master/src/auth/credential.ts#L272
Clearly, Dynamic Links API requires additional OAuth2 scopes in the token. You're better off using some OAuth2 library for this use case. If you were using Java or Python, Google Cloud provides libraries that handles this for you.
I solve the problem with a helpful GitHub user. If anyone get the same problem,press this link it will be helped. https://github.com/firebase/firebase-admin-node/issues/111