Autodesk Forge Error When Accessing API in Node - node.js

I have a 3-legged authentication token, and for some reason when I access the API, I get the following error:
"reason":"Only 2 legged service tokens are allowed to access this api."
This is how I access the API (using the npm package curlrequest, and replacing with my token):
var options = {
url: 'https://developer.api.autodesk.com/project/v1/hubs',
method: 'GET',
headers: {
'Authorization': 'Bearer <Token>'
}
};
curl.request(options, function (err, parts) {
parts = parts.split('\r\n');
var data = parts.pop()
, head = parts.pop();
console.log(data);
});
Am I doing something wrong? Is it only possible to access the Data Management API with a 2-legged token?
Thanks.

So, yes, you can only use 2-legged tokens on the Data Management API. You cannot use 3-legged tokens instead of 2-legged ones, they are meant to do different things.

Related

Node.js Axios HTTP request with bearer token returning undefined

I've seen many posts on Stack that are close to what I need, but don't fully answer my question (I'm pretty green with Node). I'm working on connecting a Twitch/Tiltify donation campaign to a Raspberry Pi via Node.js/Axios. I'd like the Pi to regularly check for new donations, then activate physical circuits (solenoid valves etc.) to be viewed live on the stream. Here's my code so far:
const axios = require('axios');
axios.get('URL_GOES_HERE', {
headers: {
'Authorization' : 'Bearer MY_TILTIFY_ACCESS_TOKEN'
}
})
.then(response => {
console.log(response.data.url);
console.log(response.data.explanation);
})
.catch(error => {
console.log(error);
});
I assume that MY_TILTIFY_ACCESS_TOKEN is the access token I generated from within my Tiltify account. I'm confused, however, about what value to put in URL_GOES_HERE. The somewhat sparse Tiltify API docs give two possible URLS: https://tiltify.com/oauth/authorize and https://tiltify.com/oauth/token. Or am I supposed to put my bearer credentials directly into the URL of a useful request, like https://tiltify.com/api/v3/user? I've tried all three, and I just get undefined undefined in the console.
A nudge in the right direction is appreciated! Thanks for your time.
#benstepp over on Github ultimately answered my question. Here's the code he provided:
const axios = require('axios');
axios.get('https://tiltify.com/api/v3/campaigns/MY_CAMPAIGN_ID/rewards', {
headers: {
'Authorization' : 'Bearer MY_API_TOKEN'
}
})
.then(response => { // this is an axios response object (https://github.com/axios/axios#response-schema)
//console.log(response.data); // this is the response body from tiltify (https://tiltify.github.io/api/endpoints/campaigns-id-donations.html)
//console.log(response.data.data); // this is the .data property of our responses
response.data.data.map((reward) => {
// the name/amount of the recent donations
console.log(`${reward.name}`)
})
})
.catch(error => {
console.log(error);
});
The /authorize endpoint is used for the Web Server OAuth Authentication Flow and User-Agent OAuth Authentication Flow.
The /token endpoint is used for the Username-Password OAuth Authentication Flow and the OAuth Refresh Token Process.
So first you need to get Authorized to be able to use Tiltify api. For that you need to use either of the flow
https://tiltify.com/oauth/authorize
https://tiltify.com/oauth/token
Assuming you used token route, you will get a response something like this:
{ "access_token":"token", "token_type":"bearer", "refresh_token":"refresh_token" }
Then using the access_token you got from the response you will call the api routes so in URL GOES HERE will be your api routes like
/campaigns/:id
causes/:id
with which you'll use Authorization: Bearer <access_token> in headers

Safest way to persist logged in state when forced to use basic auth

Whats the best/safest way to store credentials for subsequent calls to an API using Basic Auth which I dont have control over?
We're apparently only using basic auth for our beta testing phase thankfully, but I have lived long enough to know that sometimes security details get lost on product people and beta users reuse passwords, so want to make it as secure as I can just in case despite it being a temporary thing.
Currently I am using session storage to store credentials in base64 form. Is that really the best that can be done?
Note that in order to get rid of the ugly browser login prompt, the WWW-Authenticate header has been removed from the server response. This means that the browser no longer 'magically' caches auth info for subsequent calls, so I need to do it manually somehow.
This what I am currently using. While it technically works, are there ways I can decrease the security risks?
const baseUrl = getServerBaseUrl()
const authenticationService = {
authenticate: (username, password) => {
const token = btoa(`${username}:${password}`)
sessionStorage.setItem('credentials', token)
return axios.get(baseUrl, {
headers: {
Authorization: `Basic ${token}`,
},
})
},
checkAuthentication: () => {
return axios.get(baseUrl, {
headers: {
Authorization: `Basic ${sessionStorage.getItem('credentials')}`,
},
})
},
}

Get Microsoft GRAPH access token from Nodejs script

This question builds on How to get Microsoft Graph API Access token from Node Script?, however, as a first-time user of, I don't have the required reputation for commenting on the accepted answer in that thread.
The thing is, I tried to implement the approach suggested by the accepted answer, but somewhere it goes wrong. The below code is part of an async function, and I can already tell you that the ONEDRIVE_TENANT_URI is of the format XXX.onmicrosoft.com.
const endpoint = `https://login.microsoftonline.com/${process.env.ONEDRIVE_TENTANT_URI}/oauth2/token`;
const requestParams = {
grant_type: "client_credentials",
client_id: process.env.ONEDRIVE_APP_ID,
client_secret: process.env.ONEDRIVE_CLIENT_SECRET,
resource: "https://graph.windows.net"
};
const authResponse = await request.post({
url: endpoint,
form: requestParams
});
authResponse gets, as its body, just a string with the requestParams as defined above filled out.
If I submit the post request via Postman, with the same parameters as x-www-form-urlencoded, I DO get an access_token in the response body.
So... What do I do wrong? Maybe - but I don't think so - it's because this function is invoked by a (for testing purposes) POSTMAN GET request with a json-formatted body?
You can download the sample here. And fill in the credentials in config.js. You can find them from Azure portal.
This is the code to get access token.
auth.getAccessToken = function () {
var deferred = Q.defer();
// These are the parameters necessary for the OAuth 2.0 Client Credentials Grant Flow.
// For more information, see Service to Service Calls Using Client Credentials (https://msdn.microsoft.com/library/azure/dn645543.aspx).
var requestParams = {
grant_type: 'client_credentials',
client_id: config.clientId,
client_secret: config.clientSecret,
resource: 'https://graph.microsoft.com'
};
// Make a request to the token issuing endpoint.
request.post({ url: config.tokenEndpoint, form: requestParams }, function (err, response, body) {
var parsedBody = JSON.parse(body);
console.log(parsedBody);
if (err) {
deferred.reject(err);
} else if (parsedBody.error) {
deferred.reject(parsedBody.error_description);
} else {
// If successful, return the access token.
deferred.resolve(parsedBody.access_token);
}
});
return deferred.promise;
};
You will get the access token successfully.
You've got two issues going on.
The first isn't an issue yet, but it will be once you try to call Microsoft Graph. The resource should be graph.microsoft.net, not graph.windows.net. The graph.windows.net refers to the legacy Azure AD Graph API, not Microsoft Graph.
The other issue, which is the root cause of this error, is await request.post. Request doesn't natively support promises. From the Request the documentation:
request supports both streaming and callback interfaces natively. If you'd like request to return a Promise instead, you can use an alternative interface wrapper for request. These wrappers can be useful if you prefer to work with Promises, or if you'd like to use async/await in ES2017.
Several alternative interfaces are provided by the request team, including:
request-promise (uses Bluebird Promises)
request-promise-native (uses native Promises)
request-promise-any (uses any-promise Promises)

How to call Management API v2 to send verification mail from within a rule?

I'm writing a rule in Auth0 to trigger a verification email if a certain condition is met. To make the example small I have included the code which I am using to send the verification mail (I have removed out the unwanted code).
var url = 'https://myname.au.auth0.com/api/v2/jobs/verification-email';
var token = 'Bearer {{token}}'; //This is where the problem is how do I get the token
var userId = user.user_id;
request.post({
url: url,
headers: {
Authorization: 'Bearer {{token}}',
},
json: {
"user_id": user.user_ID
},
timeout: 5000
},
function(err, res, body) {
console.log(err);
console.log(res);
});
In the body I get the following error
{ statusCode: 400,
error: 'Bad Request',
message: 'Bad HTTP authentication header format',
errorCode: 'Bearer' }
I guess I need to pass in the access token or something like that in the header. How do I get this done?
I also saw the following article (https://auth0.com/docs/email/custom), however I'm not sure what secretToken is?
Starting from the bottom, the article (https://auth0.com/docs/email/custom) is aimed at users that want additional flexibility and use their own custom email handling. The secretToken on that example it's just to illustrate a possible - and very simple - way that their own custom email API could validate that they were being called from Auth0; in conclusion it would work almost as an API key.
If you only need to trigger a verification email through the system provided by Auth0 you're using the correct approach (Management API v2). You have more than one way to obtain a token that allows you to call this API:
Using the client credentials grant
Using the Auth0 Management API v2 Explorer
The second option would be the easiest to get started, but do take in consideration that there's a deprecation notice for that one.
Once you obtain the token, you also need to correctly pass it to the API. The code you showed may be only sample code, but make sure that you don't end up including the Bearer scheme twice, more specifically var token = 'Bearer {{token}}'; should instead just be var token = '{{token}}'; and then you would use the token variable when creating the HTTP header.
Just created the below empty rule that will get called when user tries to login and email is not yet verified and it works like a charm :D
function (user, context, callback) {
if (!user.email_verified) {
console.log("User is: " + user.user_id);
var ManagementClient = require('auth0#2.6.0').ManagementClient;
var management = new ManagementClient({
token: auth0.accessToken,
domain: auth0.domain
});
var new_userobj = {user_id:user.user_id};
management.sendEmailVerification(new_userobj,callback(new UnauthorizedError('Please click on the link in the email we have sent you to continue to login.')));
} else {
return callback(null, user, context);
}
}
I received the same error when using the wrong token, though for a different api call. I recreated your issue by using a user's access_token obtained by calling {{api-audience}}users/{{user_id}}. That token should look something like this: A1bCd2efg34IJkl5
Try using a client's access_token obtained by making this call:
curl --request POST \
--url https://{{domain}}/oauth/token \
--header 'content-type: application/json' \
--data '{
"client_id":"{{client_id}}",
"client_secret":"{{client_secret}}",
"audience":"{{audience}}",
"grant_type":"client_credentials"
}'
That token will be a full JWT.

What to do with oauth2 access_token

After going through multiple steps of OAuth2, what should be done with the access_token once it is received?
app.get('/oauth2', function(req, res) {
var code = req.query.code;
var url = "https://.../oauth/access_token";
var options = {
url: url,
method: "POST",
form: {
client_id: '...',
client_secret: '...',
grant_type: 'authorization_code',
redirect_uri: 'http://localhost:8080/oauth2',
code: code,
},
json: true
}
request(options, function(err, response, body) {
// I need to save the user in database if she doesn't exist
// Then redirect, but should I pass the access_token to the redirect?
res.redirect('/'); // or res.redirect('/?access_token=zzz')
}
// Also, should the access_token be encrypted
// Does it need to be saved in database?
// Does it go in local storage?
});
I will want some of the information that I receive in the reponse and so it needs to be stored in the database. But what specifically do I do with the access_token? Does it get saved to the database? Should it be encrypted? When I redirect, do I add it as a query string? Do I store it in local storage? If so, how?
First, your code includes json: true, but RFC 6749 4.1.3. Access Token Request states that parameters should be sent using the application/x-www-form-urlencoded format.
Second, the format of a response from a token endpoint is JSON. See 4.1.4. Access Token Response for details.
Third, after you get an access token, you should save it for later use. The place to save an access token in is up to you. Datebase, on-memory, and wherever you like. If you want to encrypt an access token when you save it, do it as you like.
Finally, an access token is used to call Web APIs of a resource server. In normal cases, implementations of Web APIs accept an access token in the ways defined in RFC 6750. In the specification, the following three ways are defined.
In Authorization header
As a Form parameter
As a Query parameter

Resources