Adding a custom header to HTTP request using angular.js - javascript

I am a novice to angular.js, and I am trying to add some headers to a request:
var config = {headers: {
'Authorization': 'Basic d2VudHdvcnRobWFuOkNoYW5nZV9tZQ==',
'Accept': 'application/json;odata=verbose'
}
};
$http.get('https://www.example.com/ApplicationData.svc/Malls(1)/Retailers', config).success(successCallback).error(errorCallback);
I've looked at all the documentation, and this seems to me like it should be correct.
When I use a local file for the URL in the $http.get, I see the following HTTP request on the network tab in Chrome:
GET /app/data/offers.json HTTP/1.1
Host: www.example.com
Connection: keep-alive
Cache-Control: max-age=0
If-None-Match: "0f0abc9026855b5938797878a03e6889"
Authorization: Basic Y2hhZHN0b25lbWFuOkNoYW5nZV9tZQ==
Accept: application/json;odata=verbose
X-Requested-With: XMLHttpRequest
If-Modified-Since: Sun, 24 Mar 2013 15:58:55 GMT
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.172 Safari/537.22
X-Testing: Testing
Referer: http://www.example.com/app/index.html
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
As you can see, both of the headers were added correctly. But when I change the URL to the one shown in the $http.get above (except using the real address, not example.com), then I get:
OPTIONS /ApplicationData.svc/Malls(1) HTTP/1.1
Host: www.datahost.net
Connection: keep-alive
Access-Control-Request-Method: GET
Origin: http://mpon.site44.com
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.172 Safari/537.22
Access-Control-Request-Headers: accept, origin, x-requested-with, authorization, x-testing
Accept: */*
Referer: http://mpon.site44.com/app/index.html
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
The only difference in code between these two is one is for the first the URL is a local file, and for the second the URL is a remote server. If you look at the second Request header, there is no Authentication header, and the Accept appears to be using a default instead of the one specified. Also, the first line now says OPTIONS instead of GET (although Access-Control-Request-Method is GET).
Any idea what is wrong with the above code, or how to get the additional headers included using when not using a local file as a data source?

I took what you had, and added another X-Testing header
var config = {headers: {
'Authorization': 'Basic d2VudHdvcnRobWFuOkNoYW5nZV9tZQ==',
'Accept': 'application/json;odata=verbose',
"X-Testing" : "testing"
}
};
$http.get("/test", config);
And in the Chrome network tab, I see them being sent.
GET /test HTTP/1.1
Host: localhost:3000
Connection: keep-alive
Accept: application/json;odata=verbose
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_3) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.172 Safari/537.22
Authorization: Basic d2VudHdvcnRobWFuOkNoYW5nZV9tZQ==
X-Testing: testing
Referer: http://localhost:3000/
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
Are you not seeing them from the browser, or on the server? Try the browser tooling or a debug proxy and see what is being sent out.

Basic authentication using HTTP POST method:
$http({
method: 'POST',
url: '/API/authenticate',
data: 'username=' + username + '&password=' + password + '&email=' + email,
headers: {
"Content-Type": "application/x-www-form-urlencoded",
"X-Login-Ajax-call": 'true'
}
}).then(function(response) {
if (response.data == 'ok') {
// success
} else {
// failed
}
});
...and GET method call with header:
$http({
method: 'GET',
url: '/books',
headers: {
'Authorization': 'Basic d2VudHdvcnRobWFuOkNoYW5nZV9tZQ==',
'Accept': 'application/json',
"X-Login-Ajax-call": 'true'
}
}).then(function(response) {
if (response.data == 'ok') {
// success
} else {
// failed
}
});

If you want to add your custom headers to ALL requests, you can change the defaults on $httpProvider to always add this header…
app.config(['$httpProvider', function ($httpProvider) {
$httpProvider.defaults.headers.common = {
'Authorization': 'Basic d2VudHdvcnRobWFuOkNoYW5nZV9tZQ==',
'Accept': 'application/json;odata=verbose'
};
}]);

my suggestion will be add a function call settings like this
inside the function check the header which is appropriate for it. I am sure it will definitely work. it is perfectly working for me.
function getSettings(requestData) {
return {
url: requestData.url,
dataType: requestData.dataType || "json",
data: requestData.data || {},
headers: requestData.headers || {
"accept": "application/json; charset=utf-8",
'Authorization': 'Bearer ' + requestData.token
},
async: requestData.async || "false",
cache: requestData.cache || "false",
success: requestData.success || {},
error: requestData.error || {},
complete: requestData.complete || {},
fail: requestData.fail || {}
};
}
then call your data like this
var requestData = {
url: 'API end point',
data: Your Request Data,
token: Your Token
};
var settings = getSettings(requestData);
settings.method = "POST"; //("Your request type")
return $http(settings);

What you see for OPTIONS request is fine. Authorisation headers are not exposed in it.
But in order for basic auth to work you need to add: withCredentials = true; to your var config.
From the AngularJS $http documentation:
withCredentials - {boolean} - whether to to set the withCredentials
flag on the XHR object. See requests with credentials for more
information.

And what's the answer from the server? It should reply a 204 and then really send the GET you are requesting.
In the OPTIONS the client is checking if the server allows CORS requests. If it gives you something different than a 204 then you should configure your server to send the correct Allow-Origin headers.
The way you are adding headers is the right way to do it.

Chrome is preflighting the request to look for CORS headers. If the request is acceptable, it will then send the real request. If you're doing this cross-domain, you will simply have to deal with it or else find a way to make the request non-cross-domain. This is by design.
Unlike simple requests (discussed above), "preflighted" requests first
send an HTTP request by the OPTIONS method to the resource on the
other domain, in order to determine whether the actual request is safe
to send. Cross-site requests are preflighted like this since they may
have implications to user data. In particular, a request is
preflighted if:
It uses methods other than GET, HEAD or POST. Also, if POST is used to
send request data with a Content-Type other than
application/x-www-form-urlencoded, multipart/form-data, or text/plain,
e.g. if the POST request sends an XML payload to the server using
application/xml or text/xml, then the request is preflighted. It sets
custom headers in the request (e.g. the request uses a header such as
X-PINGOTHER)
Ref: AJAX in Chrome sending OPTIONS instead of GET/POST/PUT/DELETE?

You are just adding a header which server does not allow.
eg - your server is set up CORS to allow these headers only (accept,cache-control,pragma,content-type,origin)
and in your http request you are adding like this
headers: {
'Authorization': 'Basic d2VudHdvcnRobWFuOkNoYW5nZV9tZQ==',
'Accept': 'application/json',
'x-testing': 'testingValue'
}
then the Server will reject this request since (Authorization and x-testing) are not allowed.
This is server side configuration.
And there is nothing to do with HTTP Options, it is just a preflight to server which is from different domain to check if server will allow actual call or not.

For me the following explanatory snippet worked. Perhaps you shouldn't use ' for header name?
{
headers: {
Authorization: "Basic " + getAuthDigest(),
Accept: "text/plain"
}
}
I'm using $http.ajax(), though I wouldn't expect that to be a game changer.

Related

GitHub API v3: Getting 404 error on creating issues

I'm following GitHub Docs try to get issue list and post issues.
I've managed to get the issue list using
GET https://api.github.com/repos/wheatup/wheatup.github.io/issues
But when I try to post an issue to the repo, I got a 404 error with following body:
{
"message": "Not Found",
"documentation_url": "https://docs.github.com/rest/reference/issues#create-an-issue"
}
Here's my post request:
URL
POST https://api.github.com/repos/wheatup/wheatup.github.io/issues
Headers
Accept: application/vnd.github.v3+json
Accept-Encoding: gzip, deflate, br
Accept-Language: en,zh-CN;q=0.9,zh;q=0.8,ja;q=0.7,zh-TW;q=0.6,sr;q=0.5,pl;q=0.4,la;q=0.3
Authorization: token d7fa1e545c*******************31957a97e06
Cache-Control: no-cache
Connection: keep-alive
Content-Length: 79
Content-Type: application/json
DNT: 1
Host: api.github.com
Origin: http://localhost:3000
Pragma: no-cache
Referer: http://localhost:3000/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36
Body
{
title: "Test",
body: "test content",
labels: [],
assignees: [],
milestone: 1
}
This is how I post the request:
const result = await axios.post('https://api.github.com/repos/wheatup/wheatup.github.io/issues', {
title: 'Test',
body: 'test content',
labels: [],
assignees: [],
milestone: 1,
}, {
headers: {
'Authorization': 'token d7fa1e545c*******************31957a97e06',
'Content-Type': 'application/json',
'Accept': 'application/vnd.github.v3+json'
}
});
My repo is public, did I miss something? Any help would be greatly appreciated!
It seems you are missing the github token in the request. I get 404 on my local until I add the bearer token. Then I get 401 because I am not using an actual bearer token to hit your repo. So once you add that part, it all should work.
Solution 1:
const result = await axios.post('https://api.github.com/repos/wheatup/wheatup.github.io/issues', {
title: 'Test',
body: 'test content',
// labels: [], --> Since empty, commented out as it is optional param
// assignee: '', --> Since empty, commented out as it is optional param. Also you had a typo and this attributes expects string not array
milestone: 1,
}, {
headers: {
'Authorization': `Bearer ${githubToken}`,
'Content-Type': 'application/json',
'Accept': 'application/vnd.github.v3+json'
}
});
When dealing with github API, I would suggest use their toolkit instead because you only need to provide the token once and then subsequent request can just have the data provided to them
Alternative Solution 2: --> This only applies to not have to deal with passing bearer token on every request so ignore if you rather keep using axios.
const octokit = new Octokit({ auth: githubToken });
const response = await octokit.request('POST /repos/{owner}/{repo}/issues', {
owner: 'wheatup',
repo: 'wheatup.github.io',
title: 'Test',
body: 'test content',
milestone: 1,
});
EDIT
Solution 3: -> Actual solution to the problem provided above
When dealing with OAuth apps there are some steps to take
Users are redirected to request their GitHub identity
Users are redirected back to your site by GitHub
Your app accesses the API with the user's access token
NOTE: When calling the request identity make sure to require the scope necessary for the API calls to make. In this case the 404 was received due to token not having proper permissions to the repo as scope was missing.
More information about oauth API calls can be found here
https://developer.github.com/apps/building-oauth-apps/authorizing-oauth-apps/

Upload a custom image to Spotify playlist

I'm trying to upload a custom image to my playlist on Spotify. Here's what happens: I make a request to the API to create a playlist using AJAX (this works) and then I want to upload a custom image to that newly made playlist also using AJAX. I've been following Spotify's guide on how to do that and believe that the headers, scopes, content type, etc... are all correct. Here is the code for uploading the image:
var playlistId = "newly_created_playlist_id_here";
var token = "access_token_here";
var url = c.toDataURL({ // encodes canvas image (declared as "c" in another file) to base64 jpeg format
format: 'jpeg', // file where "url" is declared is imported via the import / export method
quality: 0.8 // canvas is successfully encoded to jpeg base64
});
$.ajax({
url: "https://api.spotify.com/v1/playlists/" + playlistId +"/images",
type: 'PUT',
body: url,
headers: {
"Authorization": "Bearer " + token,
"Content-Type": "image/jpeg; charset=utf-8"
},
contentType: "image/jpeg",
error: function(err) {
console.log('Error: ' + err);
},
success: function(data) {
alert('Load was performed.');
}
});
I however receive a error 400 from Spotify as seen below:
PUT https://api.spotify.com/v1/playlists/my_playlist_id/images
400
Here is the HTTP header file contents:
Request URL: https://api.spotify.com/v1/playlists/my_playlist_id/images
Request Method: PUT
Status Code: 400
Remote Address: 35.186.224.25:443
Referrer Policy: no-referrer-when-downgrade
access-control-allow-credentials: true
access-control-allow-headers: Accept, App-Platform, Authorization, Content-Type, Origin, Retry-After, Spotify-App-Version, X-Cloud-Trace-Context
access-control-allow-methods: GET, POST, OPTIONS, PUT, DELETE, PATCH
access-control-allow-origin: *
access-control-max-age: 604800
alt-svc: clear
cache-control: private, max-age=0
content-encoding: gzip
content-length: 86
content-type: application/json
date: Mon, 15 Jun 2020 09:53:52 GMT
server: envoy
status: 400
strict-transport-security: max-age=31536000
via: HTTP/2 edgeproxy, 1.1 google
x-content-type-options: nosniff
x-robots-tag: noindex, nofollow
:authority: api.spotify.com
:method: PUT
:path: /v1/playlists/my_playlist_id/images
:scheme: https
accept: application/json, text/javascript, */*; q=0.01
accept-encoding: gzip, deflate, br
accept-language: en-GB,en-US;q=0.9,en;q=0.8
authorization: Bearer my_access_token
content-length: 0
content-type: image/jpeg
origin: http://127.0.0.1:5500
referer: http://127.0.0.1:5500/index.html
sec-fetch-dest: empty
sec-fetch-mode: cors
sec-fetch-site: cross-site
user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36
Just to re-iterate what I've said earlier for clarification, The playlist is created with no errors and the image is encoded to base64 jpeg successfully too however when I try to upload the image to the new playlist, I receive the error 400. A new access token is also generated successfully.
I am using the following scopes when requesting access from the user:
ugc-image-upload
playlist-modify-public
playlist-modify-private
which are needed as described in the Spotify documentation.
I have no idea what I'm doing wrong here and I haven't found any other questions across the internet that answer my problem so any help is greatly appreciated!
This caused me a similar headache - it does work but the encoding of the image must be exact:
No newlines or spaces
Nothing like data:image/jpeg at the start of the string (see this answer)
While not relevant to the OP, the main issue in my case was my editor (VScode) adding a new line to the end of the text file with the encoded image when it was saved, which caused it to be rejected by the Spotify API.
For anyone else looking at this, I got it working by starting with a very basic base64 encoded image (see below) and then building up to the functionality I needed.
iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==
(A red dot, taken from this question.)

Javascript Fetch API Cors : Doesen't pass access control check

I am dealing with an external api. I want to post some data so i set a token in the headers to be able to access the api.
I am told that my test origin has been whitelisted http://127.0.0.1:8081/
However i get the following error.
Failed to load
https://external-api.com/api/transactions/ad2d7a69-f723-4798-9fa5-a95a76d65324/document:
Response to preflight request doesn't pass access control check: The
value of the 'Access-Control-Allow-Origin' header in the response must
not be the wildcard '*' when the request's credentials mode is
'include'.
async submitDocument(transationId, token, base64) {
const url = host + "/api/transactions/" + transationId + "/document"
const body = {
"image": base64,
}
let headers = new Headers();
headers.set('Content-type', 'application/json');
headers.set('token', token);
const request = {
method: 'POST',
body: JSON.stringify(body),
mode: 'cors',
headers: headers,
credentials: 'include'
}
const data = await fetch(url, request);
const response = await data.json();
return response;
}
This function call is being made browser side on the following page. http://127.0.0.1:8081/
Response from server
Request URL: https://externalapi.com/api/transactions/f400aaec-3fde-4458-a36e-fe03d550fc00/document
Request Method: OPTIONS
Status Code: 200
Remote Address: 54.194.37.150:443
Referrer Policy: no-referrer-when-downgrade
Access-Control-Allow-Headers: content-type, token
Access-Control-Allow-Methods: GET,POST,PUT,DELETE
Access-Control-Allow-Origin: *
Access-Control-Max-Age: 0
Connection: keep-alive
Content-Length: 0
Date: Fri, 22 Jun 2018 15:29:27 GMT
Server: nginx
Vary: Origin
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-GB,en-US;q=0.9,en;q=0.8
Access-Control-Request-Headers: content-type,token
Access-Control-Request-Method: POST
Cache-Control: no-cache
Connection: keep-alive
Host: externalapi.com
Origin: http://127.0.0.1:8081
Pragma: no-cache
Referer: http://127.0.0.1:8081/
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36
just read the error message carefully! Your domain must not be whitelistet with '*'.
It has to be 'http://127.0.0.1:8081'. You have to ask external-api.com to recheck it.
In your request you have credentials set in a token header and the Origin of your request is:
Origin: http://127.0.0.1:8081
The request in this case will proceed only if the server answers with:
Access-Control-Allow-Origin: http://127.0.0.1:8081
Otherwise the request is blocked by the browser
Check here for more details:
https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#Examples_of_access_control_scenarios
In particular the section "Requests with credentials"

Cache control in javascript request

control:no-cache` field into my request when requesting RSS feed
I cant quit figure what values should i put in
In case of Content-type it works well but it refuses to add correctly Cachce-Control
code :
options = {uri :SUPPORT_FEED_URI,
headers : {
'Content-Type': 'application/x-www-form-urlencoded',
'Cache-Control': 'no-cache'
},
}
request.get(options)
.on('error', (err) => { reject(err); })
.pipe(feedparser)
.on('end', () => { return resolve(items); });
What i get in request headers :
Accept:*/*
Accept-Encoding:gzip, deflate, sdch
Accept-Language:en-US,en;q=0.8
Access-Control-Request-Headers:cache-control <-- doesnt seems to be right Want something like Cache-Control : no-cache
Access-Control-Request-Method:GET
Connection:keep-alive
Host: xxxx.yyyy.zz
Origin:http://127.0.0.1:8888
Referer:http://127.0.0.1:8888/webconsole/
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36
content-type:application/x-www-form-urlencoded
Your capture is a CORS pre-flight (OPTIONS) request as the URL is on a different domain or considered to be different-origin.
Such a request will not include custom headers, they are added to Access-Control-Request-Headers instead to see if the destination server will allow them.
If the destination server responds with an acceptable allow- response the subsequent GET will include your header.
Depends what you are trying to achieve.
If you are trying to force a non-cached response and dont have control over the server, one thing you can do is to add a fake query param like this.
options = {
uri :`${SUPPORT_FEED_URI}?${new Date().getTime()}`,
headers : {
'Content-Type': 'application/x-www-form-urlencoded'
},
}
For more information on the 'Cache-Control' header see the top answer here.
What's the difference between Cache-Control: max-age=0 and no-cache?

$http post return 400 on google chrome angularjs

well I have this issue when I use $http.post of angularjs on google chrome it always returned with error 400 which is bad request, however when I tried on Mozilla Firefox it works fine!
this is the $http services code
$http({
'method': "POST",
'url': "http://example.com",
'data': data,
'withCredentials': true,
'cache': false,
headers: {
'Content-type': 'application/json',
'authTokens': sessionServices.get('userLogin').userLoginTokens,
'JSESSIONID': sessionServices.get('JSESSIONID')
}
}).
success(function(data, response, headers, status) {
console.log("sucess");
}).
error(function(data, response) {
console.log("failed");
});
this is the example data intput on the $http request it self
data = [123415, 32324123, 1123124123, 1213123]
NOTE*
the url that I submitted to which is the backend is in another domain so for example I deployed the application on http://example1.com while the backend is on http://example.com, at first I thought it was CORS issue but then apparently I passed the OPTION call and when moved to the second call which is the POST request it self then it returned with the error 400
apparently the chrome ignores my custom headers option set which is 'application/json', but in chrome it returned differently. you could see the returned call below
Remote Address:example1.com
Request URL:example.com
Request Method:POST
Status Code:400 Bad Request
Request Headers
view source
Accept:application/json, text/plain, */*
Accept-Encoding:gzip,deflate
Accept-Language:en-US,en;q=0.8,id;q=0.6,ms;q=0.4
authTokens:13f4ca0d-eb30-435b-b313-a78ed8fff5ef
Connection:keep-alive
Content-Length:313
Content-Type:application/json;charset=UTF-8 application/json
Cookie:JSESSIONID=F524FAFC1178EE3451A7D82CBAD9BE87
Host:http://example1.com
JSESSIONID:F524FAFC1178EE3451A7D82CBAD9BE87
Origin:http://example.com
Referer:http://example.com
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.124 Safari/537.36
X-Requested-With:XMLHttpRequest
Request Payload
view source
[d6fece6d-fd4b-4377-b326-7e7cdafbe02b, 6240a840-29a7-4e16-899a-2db0fde6ffdd,…]
0: "d6fece6d-fd4b-4377-b326-7e7cdafbe02b"
1: "6240a840-29a7-4e16-899a-2db0fde6ffdd"
2: "794ae064-38f3-4324-8cda-5afaabe2347d"
3: "41d28490-624d-418d-8fda-4a0ed8c65aa2"
4: "38e06d09-1d33-42d2-b6a2-e06548743a1a"
5: "7f8e92c8-4217-443a-9830-3da78a75b1a6"
6: "ed31b19a-2b2a-4fd7-99b8-b5b61d6a881f"
7: "2b1b8636-d342-4114-9de3-40d42003790f"
Response Headers
view source
Access-Control-Allow-Credentials:true
Access-Control-Allow-Origin:example1.com
Access-Control-Expose-Headers:Jsessionid
Connection:close
Content-Language:en
Content-Length:990
Content-Type:text/html;charset=utf-8
Date:Wed, 15 Oct 2014 15:25:48 GMT
Server:Apache-Coyote/1.1
Vary:Origin
do you have this issue as well ?? could you guys help me ??
Maybe it's because of the incorrect Content-Type header:
Content-Type:application/json;charset=UTF-8 application/json
In your JavaScript code there's a typo:
headers: {
'Content-type': 'application/json',
It has to be -Type, capital T. The default is application/json anyway so you can as well remove that line.
It could be that Chrome merges Content-type and Content-type whereas Firefox sends either two separate headers or only one of them.

Categories