How to make dojo.request.xhr GET request with basic authentication - https

I look at the documentation for Dojo v.1.9 request/xhr
and I cannot find example that includes basic authentication.
How and where do I include the User name and Password in the Dojo XHR options?
require(["dojo/request/xhr"], function(xhr){
xhr("example.json", {
// Include User and Password options here ?
user: "userLogin"
password: "userPassword"
handleAs: "json"
}).then(function(data){
// Do something with the handled data
}, function(err){
// Handle the error condition
}, function(evt){
// Handle a progress event from the request if the
// browser supports XHR2
});
});
Thanks.

Indeed, you should be able to pass the user and password with the user and password property in the options object.
In previous versions of Dojo this was documented, but it seems that now they aren't. However, I just tested it and it seems to add the username and password to the URL, like:
http://user:password#myUrl/example.json
Normally the browser should be capable of translating this URL so the request headers are set.
You could also set these headers manually, for example by using:
xhr("example.json", {
headers: {
"Authorization": "Basic " + base64.encode(toByteArray(user + ":" + pass))
}
}).then(function(data) {
// Do something
});
However, this requires the dojox/encoding/base64 module and the following function:
var toByteArray = function(str) {
var bytes = [];
for (var i = 0; i < str.length; ++i) {
bytes.push(str.charCodeAt(i));
}
return bytes;
};

Related

Failed to retrieve clubhouse.io api using UrlFetchApp.fetch

Problem Statement: Unable to retrieve data using clubhouse.io api
in Google sheets > Script Editor
Per developers.google.com: Certain HTTP methods (for example, GET) do not accept a payload.
However, the clubhouse v3 api expect body/payload in GET request
Here is method:
function getClubhouseStories() {
try{
var myHeaders = {"Content-Type": "application/json"};
var requestOptions = {
method: 'GET',
headers: myHeaders,
body: JSON.stringify({"query":"lable\:my label"}),
redirect: 'follow',
query: {"token": "XXXXXXXXUUIDXXXXX"},
muteHttpExceptions: true
};
var response = UrlFetchApp.fetch("https://api.clubhouse.io/api/v3/search/stories", requestOptions);
}
catch(error) {
console.error(error);
}
var responseCode = response.getResponseCode();
var responseContent = response.getContentText();
Logger.log(responseCode);
Logger.log(responseContent);
}
Returns:
responseCode >> 401
responseContent >> "{"message":"Sorry, the organization context for this request is missing. If you have any questions please contact us at support#clubhouse.io.","tag":"organization2_missing"}"
The same request works perfect via postman or bash, and requests that don't need body also work via UrlFetchApp.fetch
Tags:
#clubhouse-api #google-apps-scripts #postman
You can include the token and query parameters as part of the URL.
function getClubhouseStories() {
try {
var requestOptions = { muteHttpExceptions: true };
var parameters = {
token: 'XXXXXXXXUUIDXXXXX',
query: 'label:"my label"' // Clubhouse API requires using double quotes around multi-word labels
};
var url = "https://api.clubhouse.io/api/v3/search/stories";
var response = UrlFetchApp.fetch(buildUrl_(url, parameters), requestOptions);
} catch (error) {
console.error(error);
}
var responseCode = response.getResponseCode();
var responseContent = response.getContentText();
Logger.log(responseCode);
Logger.log(responseContent);
}
/**
* Builds a complete URL from a base URL and a map of URL parameters.
* Source: https://github.com/gsuitedevs/apps-script-oauth2/blob/master/src/Utilities.js#L27
* #param {string} url The base URL.
* #param {Object.<string, string>} params The URL parameters and values.
* #return {string} The complete URL.
* #private
*/
function buildUrl_(url, params) {
var paramString = Object.keys(params).map(function(key) {
return encodeURIComponent(key) + '=' + encodeURIComponent(params[key]);
}).join('&');
return url + (url.indexOf('?') >= 0 ? '&' : '?') + paramString;
}
Other issues you're facing are related to request options that aren't valid UrlFetchApp parameters:
Default method is 'GET', so no need to specify
Content-Type should be specified using contentType, but it defaults to "application/x-www-form-urlencoded", so no need to specify
body is not valid. Should use payload instead, but not in this case, because we need to include parameters in the URL.
redirect is not valid. Should use followRedirects, but that already defaults to true.
query is not valid. Need to manually include in the URL.
The message you received, Sorry, the organization context for this request is missing. is the error you'll receive when you fail to send an authorization token/header.
You need something like this:
var myHeaders = {"Content-Type": "application/json", "Shortcut-Token": "<token>"};
Shortcut API docs

spotify application requests authorization

I am trying to get 'access token' from spotify with the following code.
var encoded = btoa(client_id+':'+client_secret);
function myOnClick() {
console.log('clikced!');
$.ajax({
url: 'https://accounts.spotify.com/api/token',
type: 'POST',
data: {
grant_type : "client_credentials",
'Content-Type' : 'application/x-www-form-urlencoded'
},
headers: {
Authorization: 'Basic ' + encoded
},
dataType: 'json'
}).always((data)=> console.log(data));
}
however I keep getting errors:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading
the remote resource at https://accounts.spotify.com/api/token.
(Reason: CORS header ‘Access-Control-Allow-Origin’ missing).
and
readyState: 0, status: 0
Arielle from Spotify here.
Looks like you're using the Client Credentials Flow, which is one of 3 Authentication flows you can use with the Spotify API. (You can check out all 3 here)
Client Credentials is meant for server-side use only, and should not be used on the front-end, as it requires a client secret which you shouldn't be exposing!
You should use the Implicit Grant flow, which is made for use in the browser, instead. It's easy to get up and running, too!
// Get the hash of the url
const hash = window.location.hash
.substring(1)
.split('&')
.reduce(function (initial, item) {
if (item) {
var parts = item.split('=');
initial[parts[0]] = decodeURIComponent(parts[1]);
}
return initial;
}, {});
window.location.hash = '';
// Set token
let _token = hash.access_token;
const authEndpoint = 'https://accounts.spotify.com/authorize';
// Replace with your app's client ID, redirect URI and desired scopes
const clientId = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
const redirectUri = 'http://localhost:8888';
const scopes = [
'user-read-birthdate',
'user-read-email',
'user-read-private'
];
// If there is no token, redirect to Spotify authorization
if (!_token) {
window.location = `${authEndpoint}?client_id=${clientId}&redirect_uri=${redirectUri}&scope=${scopes.join('%20')}&response_type=token`;
}
Gist: https://gist.github.com/arirawr/f08a1e17db3a1f65ada2c17592757049
And here's an example on Glitch, that you can "Remix" to make a copy and start making your app: https://glitch.com/edit/#!/spotify-implicit-grant
Hope that helps - happy hacking! 👩🏼‍💻
const result = await axios({
url: this.apiLoginUrl,
method: 'post',
data: "grant_type=client_credentials",
headers: {
'Authorization': `Basic ${Buffer.from(this.clientId + ":" + this.clientSecret).toString('base64')}`,
},
});

Forms validation in Nancy not working with AJAX login requests

I'm trying to implement an extremely simple spike using Nancy as an alternative to ASP.NET MVC.
It should take a username (no password) and provide meaningful error messages on the same login page without requiring a refresh. If login was successful, the response includes the URL to navigate to.
The POCO for the response looks like this:
public class LoginResponseModel
{
public bool IsSuccess { get; set; }
public string RedirectUrl { get; set; }
public string ErrorMessage { get; set; }
}
The JS handler for the login request:
$.ajax({
url: '/login',
type: "POST",
data: { UserName: username }
}).done(function (response) {
if (response.IsSuccess) {
showSuccess();
document.location.href = response.RedirectUrl;
return;
}
showError(response.ErrorMessage);
}).fail(function (msg) {
showError("Unable to process login request: " + msg.statusText);
});
The problem I'm having is with Nancy's Forms-based authentication. I've walked through half a dozen different tutorials which all more or less do the same thing, as well as gone over the Nancy authentication demos. The one thing they all have in common is that they rely on the LoginAndRedirect extension method. I don't want to return a redirect. I want to return a result of the login attempt and let the client handle the navigation.
The IUserMapper implementation I'm using:
public class UserMapper : IUserMapper
{
public IUserIdentity GetUserFromIdentifier(Guid identifier, NancyContext context)
{
// Don't care who at this point, just want ANY user...
return AuthenticatedUser {UserName = "admin"};
}
}
The relevant part of my LoginModule action:
var result = _userMapper.ValidateUser(input.AccessCode);
if (result.Guid != null) this.Login(UserMapper.GUID_ADMIN, expiry);
return Response.AsJson(result.Response);
but for subsequent requests Context.CurrentUser is always null.
If I add the following method to the Nancy.Demo.Authentication.Forms sample it reproduces the behaviour I'm seeing in my own project, leading me to believe LoginWithoutRedirect doesn't work how I expected.
Get["/login/{name}"] = x =>
{
Guid? userGuid = UserDatabase.ValidateUser(x.Name, "password");
this.LoginWithoutRedirect(userGuid.Value, DateTime.Now.AddYears(2));
return "Logged in as " + x.Name + " now <a href='~/secure'>see if it worked</a>";
};
The problem turns out to be that Context.CurrentUser with FormsAuthentication is dependent upon a cookie which isn't set if you don't return the NancyModule.Login() response.
var result = _userMapper.ValidateUser(input.AccessCode);
if (result.IsSuccess) {
this.LoginWithoutRedirect(result.Guid);
}
return Response.AsJson(result);
In this example, the LoginWithoutRedirect call returns a Response object with the cookie set. To handle this in an Ajax scenario I've had to add a AuthToken property to the LoginAjaxResponse class, then pass the cookie like so:
var result = _userMapper.ValidateUser(input.AccessCode);
var response = Response.AsJson(result);
if (result.IsSuccess) {
var authResult = this.LoginWithoutRedirect(result.Guid);
result.AuthToken = authResult.Cookies[0].Value;
}
return Response.AsJson(result);
On the client, the Ajax response handler changes to (assuming use of jQuery cookie plugin:
$.ajax({
url: '/login',
type: "POST",
data: { UserName: username }
}).done(function (response) {
if (response.IsSuccess) {
showSuccess();
$.cookie("_ncfa", response.AuthToken); // <-- the magic happens here
document.location.href = response.RedirectUrl;
return;
}
showError(response.ErrorMessage);
}).fail(function (msg) {
showError("Unable to process login request: " + msg.statusText);
});
The AuthToken is the GUID which has been encrypted and base64-encoded. Subsequent requests with this.RequiresAuthentication() enabled will first check for this auth token cookie.
If no "_ncfa" cookie is present,the UserMapper's GetUserFromIdentifier() is never called.
If the value in Context.Request.Cookies["_ncfa"] does not result in a valid GUID when base64-decoded and decrypted, GetUserFromIdentifier() is never called.
If GetUserFromIdentifier() isn't called, Context.CurrentUser is never set.
If you want the source for a working example it's on GitHub.
LoginAndRedirect is only one option, there are equivalent methods for not redirecting (LoginWithoutRedirect), or one that picks up on whether it's an AJAX request and handles it appropriately (Login). The same applies to logging out.
This is all covered, in detail, in the documentation.

not getting response from ajax call in codeigniter

I am trying to check if the user name is available for use using ajax and codeigniter. I have problem to get the response from the codeingniter controller in my js. file but without success.
Here is the controller function, relevant to the question:
if ($username == 0) {
$this->output->set_output(json_encode(array("r" => true)));
} else {
$this->output->set_output(json_encode(array("r" => false, "error" => "Username already exits")));
}
Rest assured that I do get 1 if username already exists in thedatabase and 0 if it does not exist.
I have the following js.file
// list all variables used here...
var
regform = $('#reg-form'),
memberusername = $('#memberusername'),
memberpassword = $('#memberpassword'),
memberemail = $('#memberemail'),
memberconfirmpassword = $('#memberconfirmpassword');
regform.submit(function(e) {
e.preventDefault();
console.log("I am on the beggining here"); // this is displayed in console
var memberusername = $(this).find("#memberusername").val();
var memberemail = $(this).find("#memberemail").val();
var memberpassword = $(this).find("#memberpassword").val();
var url = $(this).attr("action");
$.ajax({
type: "POST",
url: $(this).attr("action"),
dataType: "json",
data: {memberusername: memberusername, memberemail: memberemail, memberpassword: memberpassword},
cache: false,
success: function(output) {
console.log('I am inside...'); // this is never displayed in console...
console.log(r); // is never shonw in console
console.log(output); is also never displayed in console
$.each(output, function(index, value) {
//process your data by index, in example
});
}
});
return false;
})
Can anyone help me to get the username value of r in the ajax, so I can take appropriate action?
Cheers
Basically, you're saying that the success handler is never called - meaning that the request had an error in some way. You should add an error handler and maybe even a complete handler. This will at least show you what's going on with the request. (someone else mentioned about using Chrome Dev Tools -- YES, do that!)
As far as the parse error. Your request is expecting json data, but your data must not be returned as json (it's formatted as json, but without a content type header, the browser just treats it as text). Try changing your php code to this:
if ($username == 0) {
$this->output->set_content_type('application/json')->set_output(json_encode(array("r" => true)));
} else {
$this->output->set_content_type('application/json')->set_output(json_encode(array("r" => false, "error" => "Username already exits")));
}

How can I send an AJAX request to a node.js server via HTTPS?

I have the following node.js server set up listening to port 9001
var https = require('https');
var fs = require('fs');
var qs = require('querystring');
var options = {
key: fs.readFileSync('privatekey.pem'),
cert: fs.readFileSync('certificate.pem')
};
https.createServer(options, function (req, res) {
res.writeHead(200);
console.log('Request Received!');
console.log(req.method);
if (true || req.method == 'POST') {
var body = '';
req.on('data', function (data) {
body += data;
});
req.on('end', function () {
console.log(body);
var POST = qs.parse(body);
console.log(POST);
});
}
res.end("hello, world\n");
}).listen(9001);
and I am trying to get this server to respond to an AJAX call
function form_save()
{
console.log("submitted!");
var data_obj = {
data1: "item1",
data2: "item2"
}
$.ajax({
url: 'https://adam.testserver.com:9001/',
type: "POST",
dataType: "json",
data: data_obj,
success: function() {
console.log("success!");
},
complete: function() {
console.log("complete!");
}
});
}
There are two problems occurring with my arrangement. The first is that if I start the server and then click the button that triggers my form_save() the node server does not respond and I get the following error:
submitted!
OPTIONS https://adam.testserver.com:9001/ Resource failed to load
jQuery.extend.ajaxjquery.js:3633
$.ajaxjquery.validate.js:1087
form_savew_worksheet.php:64
confirm_deletew_worksheet.php:95
jQuery.event.handlejquery.js:2693
jQuery.event.add.handlejquery.js:2468
w_worksheet.php:73
complete!
At this point if I access that url directy (https://adam.testserver.com:9001/) I get the expected "hello, world" output as well as the console message "Request Received!
GET". From this point on if I click the button to trigger my AJAX call I get a new error.
submitted!
XMLHttpRequest cannot load https://adam.testserver.com:9001/. Origin
https://adam.testserver.com is not allowed by Access-Control-Allow-Origin.
w_worksheet.php:73
complete!
I don't understand why I get this message as both my form and node server reside on the same server. Thanks for taking the time to read, I appreciate any help I can get on this. I've been stuck for a while now!
You've run into the Cross-Origin Resource Sharing (CORS) specification.
Note the OPTIONS in your output. The OPTIONS HTTP Verb is used by the browser to query the web server about the URL, not to GET its contents or POST data to it.
Your server doesn't respond with the correct header data on a CORS request, so your browser assumes it has no rights to access the data, and refuses to GET or POST to the URL.
If you truly want to let any website in the world run that AJAX request, you can do something similar to the following:
function handleOptions(request, response) {
response.writeHead(200, {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Method": "POST, GET, OPTIONS",
"Access-Control-Allow-Headers": request.headers["access-control-request-headers"]
});
response.end();
}
function server(request, response) {
if(request.method == "POST") {
handlePost(request, response);
} else if(request.method == "OPTIONS") {
handleOptions(request, response);
} else {
handleOther(response);
}
}
https.createServer(sslObj, server).listen(9001);
You can fill in the details and whether you should handle GET separately, and so on (handleOther should return an appropriate error code for each request method you don't support).

Resources