DBS API Server Error 500 on Sandbox calls - node.js

I was just experimenting with the DBS API Sandbox here (https://www.dbs.com/developers/). We have to use OAuth2 to get the access token before passing it in the header to authenticate API calls. When I tested everything out on their test client UI I got the results back from the API call.
However, when I coded my simple node app, I could successfully perform OAuth2 and get an access token, but when passed in together with the clientId, got a server error 500 from the API.
For example, the GET call to get a bank account details:
const options = {
method: 'GET',
uri: dbsHost + rootPath + '/accounts/22909292550739201999095',
headers: {
'Content-Type': 'application/json',
'accessToken': accessToken,
'clientId': clientId
}
}
request(options, (error, response, body) => {
// Server error 500
console.log(response)
})
These were the exact instructions as those given on the test client UI. On closer inspection I realised the access token I always got back had 488 characters, but that of the test client UI only had 475. Any reason for this difference? How do I know OAuth2 was performed correctly and I'm getting the right access token?
Here's how I did OAuth2:
On the frontend:
let authorizationUri = dbsHost + rootPath + '/oauth/authorize'
authorizationUri += '?client_id=' + clientId
authorizationUri += '&redirect_uri=' + redirectUri
authorizationUri += '&scope=Read'
authorizationUri += '&response_type=code'
authorizationUri += '&state=0399'
windows.location.assign(authorizationUri)
And at the redirect_uri endpoint once I get back the authorization code:
app.get('/authCallback', (req, res) => {
let authCode = req.query.code
// Encode client_id:client_secret in base-64 to pass in as Auth Basic Header
let b64 = new Buffer(clientId + ':' + clientSecret).toString('base64')
const options = {
method: 'POST',
url: dbsHost + rootPath + '/oauth/tokens',
headers: {
'Authorization': 'Basic ' + b64
},
form: {
'code': authCode,
'redirect_uri': redirectUri,
'grant_type': 'token',
'state': '0399'
}
}
request(options, (error, response, body) => {
if (error) {
console.error('Access Token Error', error.message)
return res.status(500).json('Authentication failed');
}
let json = JSON.parse(body)
let accessToken = json['access_token']
// Make a call with this access token
})
})

Related

Spotify Authorization from Node Server not working with curl

I have a node server which gets an access token from Spotify's Web API. The response looks like this:
Response:
{
"statusCode": 200,
"body": "{\"type\":\"success\",\"done\":{\"json\":{\"access_token\":\"BQDqtYhVpafUIMYtZbwmy6iJcC_wvzR9Xrw6bRDFfpL3zZYfkCp2-KZaQVS-ZoElMF1czAl_B1vEaDrtPBOElSV3D5k\",\"token_type\":\"Bearer\",\"expires_in\":3600,\"scope\":\"user-top-read\"}}}",
"headers": {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Headers": "Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token"
}
}
When I try to use the access_token on Spotify's online API tool, I get an error for incomplete JSON. I think this is because the token I generate is only 91 characters long while the code they generate is 171 characters long. Why is my auth code so short?
I want an access token so I can use this react module for accessing my top tracks.
Here is my code for getting the access token:
let getAccessToken = (queryStringParameters) => {
let url = 'https://accounts.spotify.com/api/token';
let encoded = (new Buffer(client_id + ':' + client_secret).toString('base64'));
console.log("encoded = " + encoded);
let params = {
grant_type: 'authorization_code',
username: username,
password: password,
scope: scope
};
const formParams = Object.keys(params).map((key) => {
return encodeURIComponent(key) + '=' + encodeURIComponent(params[key]);
}).join('&');
return fetch(url, {
method: 'POST',
headers: {
"Authorization": 'Basic ' + encoded,
'Accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded'
},
body: formParams
})
.then((response) => {
console.log(util.inspect(response, { showHidden: true, depth: null }));
return response.json();
})
.catch((error) => {
done({
error: error
});
});
};
According to the Authorisation Guide the authorization_code grant type only takes the code and redirect URI values. Not sure why the username and password ones you provide are even accepted, it is possible the token returned is a client credentials one as those tend to be shorter, that only access non-user related endpoints like loading Artist data, but the parameters you're providing appear to be undocumented at least in that guide.

How to get Microsoft Graph API Access token from Node Script?

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;
});

How to OneDrive API file uploads with node.js?

After a time I finally figure out how to use oAuth2 and how to create a access token with the refresh token. But I can´t find node.js samples for upload files the only thing I found was this module https://www.npmjs.com/package/onedrive-api
But this didn´t work for me because I get this error { error: { code: 'unauthenticated', message: 'Authentication failed' } }
Also if I would enter accessToken: manually with 'xxxxxxx' the result would be the same.
But I created before the upload the access token so I don´t know if this really can be a invalid credits problem. But the funny thing is if I would take the access token from https://dev.onedrive.com/auth/msa_oauth.htm where you can generate a 1h access token the upload function works. I created my auth with the awnser from this question. OneDrive Code Flow Public clients can't send a client secret - Node.js
Also I only used the scope Files.readWrite.all do I maybe need to allow some other scopes ? My code is
const oneDriveAPI = require('onedrive-api');
const onedrive_json_configFile = fs.readFileSync('./config/onedrive.json', 'utf8');
const onedrive_json_config = JSON.parse(onedrive_json_configFile);
const onedrive_refresh_token = onedrive_json_config.refresh_token
const onedrive_client_secret = onedrive_json_config.client_secret
const onedrive_client_id = onedrive_json_config.client_id
// use the refresh token to create access token
request.post({
url:'https://login.microsoftonline.com/common/oauth2/v2.0/token',
form: {
redirect_uri: 'http://localhost/dashboard',
client_id: onedrive_client_id,
client_secret: onedrive_client_secret,
refresh_token: onedrive_refresh_token,
grant_type: 'refresh_token'
}
}, function(err,httpResponse,body){
if (err) {
console.log('err: ' + err)
}else{
console.log('body full: ' + body)
var temp = body.toString()
temp = temp.match(/["]access[_]token["][:]["](.*?)["]/gmi)
//console.log('temp1: ', temp)
temp = temp.join("")
temp = temp.replace('"access_token":"','')
temp = temp.replace('"','')
temp = temp.replace('\n','')
temp = temp.replace('\r','')
//console.log('temp4: ', temp)
oneDriveAPI.items.uploadSimple({
accessToken: temp,
filename: 'box.zip',
parentPath: 'test',
readableStream: fs.createReadStream('C:\\Exports\\box.zip')
})
.then((item,body) => {
console.log('item file upload OneDrive: ', item);
console.log('body file upload OneDrive: ', body);
// returns body of https://dev.onedrive.com/items/upload_put.htm#response
})
.catch((err) => {
console.log('Error while uploading File to OneDrive: ', err);
});
} // else from if (err) { from request.post
}); // request.post({ get access token with refresh token
Can you send me your sample codes please to upload a file to OneDrive API with node.js. Would be great. Thank you
Edit: I also tried to upload a file with this
var uri = 'https://api.onedrive.com/v1.0/drive/root:/' + 'C:/files/file.zip' + ':/content'
var options = {
method: 'PUT',
uri: uri,
headers: {
Authorization: "Bearer " + accesstoken
},
json: true
};
request(options, function (err, res, body){
if (err) {
console.log('#4224 err:', err)
}
console.log('#4224 body:', body)
});
Same code: 'unauthenticated' stuff :/
How about this sample script? The flow of this sample is as follows.
Retrieve access token using refresh token.
Upload a file using access token.
When you use this sample, please import filename, your client id, client secret and refresh token. The detail information is https://dev.onedrive.com/items/upload_put.htm.
Sample script :
var fs = require('fs');
var mime = require('mime');
var request = require('request');
var file = 'c:/Exports/box.zip'; // Filename you want to upload on your local PC
var onedrive_folder = 'samplefolder'; // Folder name on OneDrive
var onedrive_filename = 'box.zip'; // Filename on OneDrive
request.post({
url: 'https://login.microsoftonline.com/common/oauth2/v2.0/token',
form: {
redirect_uri: 'http://localhost/dashboard',
client_id: onedrive_client_id,
client_secret: onedrive_client_secret,
refresh_token: onedrive_refresh_token,
grant_type: 'refresh_token'
},
}, function(error, response, body) {
fs.readFile(file, function read(e, f) {
request.put({
url: 'https://graph.microsoft.com/v1.0/drive/root:/' + onedrive_folder + '/' + onedrive_filename + ':/content',
headers: {
'Authorization': "Bearer " + JSON.parse(body).access_token,
'Content-Type': mime.lookup(file),
},
body: f,
}, function(er, re, bo) {
console.log(bo);
});
});
});
If I misunderstand your question, I'm sorry.

Execute OAuth2 with the Mailchimp API in NodeJS

I've been following MailChimp's OAuth2 tutorial (https://developer.mailchimp.com/documentation/mailchimp/guides/how-to-use-oauth2/) but got stuck when making a post request with the code and secret/key params. The closest I've gotten is a 400 Bad Request response. My code:
var args = {
headers: { "Content-Type": "application/json" },
body: "grant_type=authorization_code&client_id=" + client_id + "&client_secret=" + client_secret + "&redirect_uri=" + encoded_url + "&code=" + req.query.code,
url: "https://login.mailchimp.com/oauth2/token"
};
var r = request.post(args, function(err, req, body){
console.log(err)
console.log(req)
})
Okay, I was running in to the same thing, and finally found it. My code was very similar to yours:
this.globals.request({
method: "POST",
uri: "https://login.mailchimp.com/oauth2/token",
form: {
grant_type: "authorization_code",
client_id: this.globals.mailchimp_client_id,
client_secret: this.globals.mailchimp_client_secret,
redirect_uri: encodeURIComponent(fullUrl),
code: req.query.code
}
},
function (error, response, body) {
if (error || response.statusCode !== 200) {
self.globals.logger.debug(self.moduleName, "getMailchimpToken", "Error " + response.statusCode + "(" + response.statusMessage + ") from mailchimp: " + error, true);
body = {};
}
self.globals.logger.debug(self.moduleName, "getMailchimpToken", "got body: " + JSON.stringify(body), false);
deferred.resolve(body);
});
The problem here, and I suspect with yours, is that you are using an encoded URL in the form data, but request will encode it again. When I looked at the querystring, I saw things like
&redirect_uri=http%253A%252F%252F
where the %s were being re-encoded. Changed encodeURIComponent(fullUrl), to just fullUrl, and it worked.
One important note that was not clear to me - the redirect_uri should be the same one used in the OAuth call, including the path. Note that per the Mailchimp docs, you can vary the path in the actual call from the redirect_url used when registering the app, which is where this can be important.

Podio API addItem call

I'm trying to implement https://developers.podio.com/doc/items/add-new-item-22362 Podio API addItem call in a nodejs module. Here is the code:
var _makeRequest = function(type, url, params, cb) {
var headers = {};
if(_isAuthenticated) {
headers.Authorization = 'OAuth2 ' + _access_token ;
}
console.log(url,params);
_request({method: type, url: url, json: true, form: params, headers: headers},function (error, response, body) {
if(!error && response.statusCode == 200) {
cb.call(this,body);
} else {
console.log('Error occured while launching a request to Podio: ' + error + '; body: ' + JSON.stringify (body));
}
});
}
exports.addItem = function(app_id, field_values, cb) {
_makeRequest('POST', _baseUrl + "/item/app/" + app_id + '/',{fields: {'title': 'fgdsfgdsf'}},function(response) {
cb.call(this,response);
});
It returns the following error:
{"error_propagate":false,"error_parameters":{},"error_detail":null,"error_description":"No matching operation could be found. No body was given.","error":"not_found"}
Only "title" attribute is required in the app - I checked that in Podio GUI. I also tried to remove trailing slash from the url where I post to, then a similar error occurs, but with the URL not found message in the error description.
I'm going to setup a proxy to catch a raw request, but maybe someone just sees the error in the code?
Any help is appreciated.
Nevermind on this, I found a solution. The thing is that addItem call was my first "real"-API method implementation with JSON parameters in the body. The former calls were authentication and getApp which is GET and doesn't have any parameters.
The problem is that Podio supports POST key-value pairs for authentication, but doesn't support this for all the calls, and I was trying to utilize single _makeRequest() method for all the calls, both auth and real-API ones.
Looks like I need to implement one for auth and one for all API calls.
Anyway, if someone needs a working proof of concept for addItem call on node, here it is (assuming you've got an auth token beforehand)
_request({method: 'POST', url: "https://api.podio.com/item/app/" + app_id + '/', headers: headers, body: JSON.stringify({fields: {'title': 'gdfgdsfgds'}})},function(error, response, body) {
console.log(body);
});
You should set content-type to application/json
send the body as stringfied json.
const getHeaders = async () => {
const headers = {
Accept: 'application/json',
'Content-Type': 'application/json; charset=utf-8',
};
const token = "YOUR APP TOKEN HERE";
headers.Authorization = `Bearer ${token}`;
return headers;
}
const createItem = async (data) => {
const uri = `https://api.podio.com/item/app/${APP_ID}/`;
const payload = {
fields: {
[data.FIELD_ID]: [data.FIELD_VALUE],
},
};
const response = await fetch(uri, {
method: 'POST',
headers: await getHeaders(),
body: JSON.stringify(payload),
});
const newItem = await response.json();
return newItem;
}

Resources