Alexa node.js http request with authorization - javascript

I'm implementing a skill for Amazon Alexa.I want to determine the user's geolocation, but the http.get request is not working. I tried the request in postman and I get the desired result, but couldn't figure out what could be the problem. The request url should be like this https://api.amazonalexa.com/v1/devices/{deviceId}/settings/address with the Authorization header Authorization: Bearer {token}.
Here is my code
try{
var body = "";
console.log('Authorization ', consentToken);
var response = '';
var options = {
host: 'api.eu.amazonalexa.com',
path: '/v1/devices/'+deviceId+'/settings/address',
port: '443',
headers: {'Authorization': "Bearer "+consentToken},
method: 'GET'
};
https.get(options, function(res) {
console.log('status', res.statusCode);
if (res.statusCode >= 200 && res.statusCode < 400) {
res.on('data', function(data_) { response += data_.toString(); });
res.on('end', function() {
var data = JSON.parse(response);
console.log('data', data);
if (data.length > 0)
userLocation = data;
});
}
}).on('error', function(e) {
console.log("errrrror",e);
}).on('uncaughtException', function (err) {
console.log('uncaughtException',err);
});
}
catch(error) {
console.log('getAndProcessUserLocation',error);
}
I don't know why the https.get is not executed. No error is thrown, but I couldn't get any log from it. I followed the documentation from thr official site
https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/device-address-api

Without seeing the rest of your code, my guess is that you are not indicating to the Alexa request that you are handling it asynchronously, so the session is ending before the request completes.

Related

Problem retrieving bearer access token using timer triggered Azure javascript function

I have an Azure Timer Triggered Function that needs to make various calls to the Graph API, which means I need an OAuth2 Bearer token issued by my tenancy's AAD.
So I've written the function below, which based on code I've previously written to make Ajax calls, which makes a call to AAD to get the Bearer token I need.
I've tested the URL, Client ID, Client Secret, and Grant Type settings using Postman and they returned a valid Bearer Token for me to use.
However the code makes the call, and nothing is returned, it just seems to hang.
When test-run in the Azure portal I get a
Status 503 Service Unavailable.
async function getToken() {
return new Promise((resolve, reject) => {
try {
let https = require("https");
let url =
"https://login.microsoftonline.com/<azure_tenancy>.onmicrosoft.com/oauth2/token";
let options = {
method: "POST",
headers: {
"Content-Type": "application/json; charset=utf-8",
"Cache-Control": "no-cache"
}
};
let body = {
grant_type: "client_credentials",
client_id: "<client_id>",
client_secret: "client_secret>",
resource: "https://graph.microsoft.com"
};
var req = https
.request(url, options, res => {
let data = "";
res.on("data", chunk => {
data += chunk;
});
res.on("end", () => {
resolve(JSON.parse(data));
});
})
.on("error", err => {
throw new Exception(e.message);
});
req.write(JSON.stringify(body));
req.end();
} catch (e) {
context.log("error caught");
reject(e);
}
});
}
Postman returns:
{
"token_type": "Bearer",
"expires_in": "3600",
"ext_expires_in": "3600",
"expires_on": "1558542984",
"not_before": "1558539084",
"resource": "https://graph.microsoft.com",
"access_token": "eyJ...e8mw"
}
So I know the URL, ID, and Secret I'm passing are correct. It must be something else in the code but I'm baffled as to what. Any clues?

difference between api call and on postman

I was using Azure Speech rest api. And i tried it on post man with a .wav file and it successfully return the result. However, when i call api from my node.js code. It always return Unsupported Audio Format even though i give the same audio file. Can anyone tell me what's the difference of them? Or what did Postman do to make it work?
Below is how i call speech api by node.js.
'use strict';
const request = require('request');
const subscriptionKey = 'MYSUBSCRIPTIONKEY';
const uriBase = 'https://westus.stt.speech.microsoft.com/speech/recognition/conversation/cognitiveservices/v1?language=en-US';
const options = {
uri: uriBase,
body: 'speech.wav',
headers: {
'Content-Type': 'application/json',
'Ocp-Apim-Subscription-Key' : subscriptionKey,
'Transfer-Encoding': 'chunked',
'Expect': '100-continue',
'Content-type':'audio/wav; codec=audio/pcm; samplerate=16000'
}
};
request.post(options, (error, response, body) => {
if (error) {
console.log('Error: ', error);
return;
}
let jsonResponse = JSON.stringify(JSON.parse(body), null, ' ');
console.log('JSON Response\n');
console.log(jsonResponse);
});
You can try this
fs.readFile('/path/to/my/audiofile.wav', function (err, data) {
if (err) throw err;
var options = {
host: 'https://westus.stt.speech.microsoft.com/speech/recognition/conversation/cognitiveservices/v1?language=en-US',
method: 'POST',
headers: { 'Content-Type': 'audio/wav' }
};
var req = http.request(options, function(res) {
// Handle a successful response here...
});
req.on('error', function(e) {
// Handle an error response here...
});
// Write the audio data in the request body.
req.write(data);
req.end();
});

HTTP POST in Espruino for Microcontrollers

I recently got myself an esp8266-12e module and loaded the ESPRUINO.js firmware on it. I am trying execute a post request from the device, but the device always returns a 'no connection' error when trying to POST.
To troubleshoot I have ran a GET request to the same URL, and the request was successful, this means that internet is working on the device and communication with the intended server is possible.
I then moved on to see if there were errors in my HTTP POST code, I ran the same code in a node.js app and it successfully posted to the server.
Here is the code below, I removed the exact address of my server and my wifi/pass info.
var http = require("http");
var wifi = require("Wifi");
var sdata = {
deviceID: 'esp-12',
};
var options = {
hostname: 'immense-XXXXXX-XXXXX.herokuapp.com',
method: 'POST',
path:'/MXXXXXX',
headers: {
'Content-Type': 'application/json'
}
};
var req = http.request(options, function(res) {
console.log('Status: ' + res.statusCode);
console.log('Headers: ' + JSON.stringify(res.headers));
res.setEncoding('utf8');
res.on('data', function(body) {
console.log('Body: ' + body);
});
});
req.on('error', function(e) {
console.log('problem with request: ' + e.message);
});
payload = JSON.stringify(sdata);
req.write(payload);
req.end();
terminal response from device after execution
problem with request: no connection
Here is the documentation for Espruino.js HTTP module.
https://www.espruino.com/Reference#http
Can any of the JS gurus see an issue with the request?
Turns out the http post request requires the 'content-length' header to function correctly.
Here is the working post request model for anyone who may need it. Note: Payload has already been formatted as a JSON object.
function postX(payload) {
var options = {
host: 'url',
port: '80',
path:'/ext',
method:'POST',
headers: { "Content-Type":"application/json", "Content-Length":payload.length }
};
var req = require("http").request(options, function(res) {
res.on('data', function(data) {
console.log("-->"+data);
});
res.on('close', function(data) {
console.log("==> Closed.");
ticksSinceConnect = 0;
});
});
req.end(payload);}

Cannot make a basic HTTP auth with node request module

I am testing my app with mocha and I would like to test a HTTP response header code depending on the credentials that I sent to it with a basic HTTP authentication.
In the client side, I made the AJAX call to the server like this:
$.ajax({
type: 'GET',
url: url,
beforeSend: function(xhr){
xhr.setRequestHeader("Authorization", "Basic " +btoa("username:password") );
},
success:function(rsp){
// do whatever I need;
}
});
And it works perfectly. It the credentials are wrong, then the website will respond wit a 302
In my test file (mocha), I try to sent the same request but for some reason it does not work.
Here is the different way I tried:
it('should return 302 because wrong credentials', function(done){
var auth = "Basic " +new Buffer("username:password").toString('base64');
var options = {
url: url,
headers: {
"Authorization": auth
}
};
request.get(options, function(err, res, body){
console.log(res.statusCode);
assert.equal(302, res.statusCode);
done();
});
});
-----------------------
it('should return 302 because wrong credentials', function(done){
request.get(url,
{
'auth': {
'username':'username',
'password':'password'
}
},
function(err, res, body) {
assert.equal(302, res.statusCode);
done();
});
});
But, in anyway, I get a HTTP 200 response code.
So why? And how should I handle it?
Ps: For those who are very cautious, the client is not to be used publicly and thus I allow myself to put credentials in it.
EDIT: To be more precise, you will find below the server code (NodeJS) which handle the request
function checkAuth(req, result, next){
var header = req.headers['authorization'];
// Ignore the preflight OPTION call
if(header != undefined){
var tmp = header.split(/\s+/).pop();
var credentials = new Buffer(tmp, 'base64').toString();
var parts = credentials.split(/:/);
var username = parts[0];
var password = parts[1];
bcrypt.compare(username, config.get.username, function(err, res){
if(res){
bcrypt.compare(password, config.get.password, function(err, res){
if(res){
next();
} else {
return result.redirect('/');
}
});
} else {
return result.redirect('/');
}
});
} else {
return result.redirect('/');
}
}
app.get('/server', checkAuth, getData.getMessages);
And the method getData.getMessage() return the following:
return result.status(200).json(res);
request automatically follows redirects so you'll need to disable followRedirect to read 3xx responses.
var options = {
url: url,
followRedirect: false,
headers: {
"Authorization": auth
}
};
For HTTP Basic authentication you can also use http-auth module.
// Authentication module.
var auth = require('http-auth');
var basic = auth.basic({
realm: "Simon Area.",
file: __dirname + "/../data/users.htpasswd" // gevorg:gpass, Sarah:testpass ...
});
// Creating new HTTP server.
http.createServer(basic, function(req, res) {
res.end("Welcome to private area - " + req.user + "!");
}).listen(1337);

node.js http and bing search api

I am trying to use the Bing Search API to return a JSON string. I first tried using the following url as per Azure's explore website (https://datamarket.azure.com/dataset/explore/5BA839F1-12CE-4CCE-BF57-A49D98D29A44):
'https://api.datamarket.azure.com/Bing/Search/v1/Composite?Sources=%27web%27&Query=%27NGI%20SPA%27&Market=%27en-US%27'
After, I found a SO thread Using the new Bing API (nodejs) which suggested I use a url of the form:
https://user:<YourDefaultAccountKey>#api.datamarket.azure.com/Bing/SearchWeb/Web?Query=%27leo%20fender%27&Market=%27en-US%27&$top=50&$format=JSON
Both of these return status 401 (Authentication Failure):
STATUS: 401
HEADERS: {"content-type":"application/json; charset=utf-8","server":"Microsoft-IIS/8.0","jsonerror":"true","x-powered-by":"ASP.NET","access-control-allow-origin":"*","access-control-allow-credentials":"false","access-control-allow-headers":"Authorization, DataServiceVersion, MaxDataServiceVersion","access-control-expose-headers":"DataServiceVersion, MaxDataServiceVersion","access-control-allow-methods":"GET, POST, OPTIONS","access-control-max-age":"604800","date":"Wed, 02 Jul 2014 17:23:29 GMT","content-length":"91"}
BODY: {"Message":"There was an error processing the request.","StackTrace":"","ExceptionType":""}
I have also tried other various combinations of URLs to no avail. My code is below:
var url = require('url');
var http = require('http');
var serviceRootURL = 'https://api.datamarket.azure.com/Bing/Search/v1/Composite?Sources=%27web%27&Query=%27NGI%20SPA%27&Market=%27en-US%27'
var params = 'hi';
var dataURL = url.parse(serviceRootURL);
var post_options = {
hostname: dataURL.hostname,
port: dataURL.port || 80,
path: dataURL.path,
method: 'GET',
headers: {
'Content-Type': 'application/json; charset=utf-8',
'Content-Length': params.length
}
};
var req = http.request(post_options, function(res) {
console.log('STATUS: ' + res.statusCode);
console.log('HEADERS: ' + JSON.stringify(res.headers));
res.setEncoding('utf8');
res.on('data', function (chunk) {
console.log('BODY: ' + chunk);
});
});
req.on('error', function(e) {
console.log('problem with request: ' + e.message);
});
// write data to request body
req.write('data\n');
req.write('data\n');
req.end();
Any idea why I am getting an authentication failure?
You can use this module that encapsulates the requests, so you can use it
like:
var Bing = require('node-bing-api')({ accKey: "your-account-key" });
Bing.web("leo fender", function(error, res, body){
console.log(body);
},
{
top: 50,
market: 'en-US'
});
It works with the Azure version. You only have to replace your account key.
Got it working with request...weird
var request = require('request');
var _ = require('underscore');
var searchURL = 'https://user:<TIPE YOUR KEE HEER>#api.datamarket.azure.com/Bing/SearchWeb/v1/Web?Query=%27xbox%27&$top=10&$format=JSON';
var http = request( searchURL, function(err, resp, body)
{
if ( err )
{
throw err;
}
var a = JSON.parse(body);
console.log(a.d.results);
});
you can use jsearch module. install ;
npm install jsearch
usage;
js.bing('queryStringYouWant',10,function(response){
console.log(response) // for Bing results
})

Categories

Resources