React request is being sent without an Authorization header - reactjs

I am trying to pass a bearer token, to the fastify http server, in my headers.
I set the headers inside my request as:
...
const headers = {
Accept: 'application/json',
'Content-Type': 'application/json'
}
const token = localStorage.getItem('token')
if (token) {
headers['Authorization'] = `Bearer ${token}`
}
const newOptions = {
...options,
mode: 'no-cors',
headers
}
console.log('options:', newOptions)
return fetch(url, newOptions)
My console.log prints:
options: {
mode: "no-cors",
headers: {
Accept: "application/json",
Content-Type: "application/json",
Authorization: "Bearer NQ9xQLmYtq92aT8JHHRd7DGZJ..."
}
}
From the Chrome network tab, I look at the headers, and Authorization is just not present there. My route handler function is below:
async function user(server, options) {
server.route({
method: 'GET',
url: '/user/:email',
handler: async (req, res) => {
const username = req.params.email
console.log('user email:', username)
console.log('headers:', req.headers)
res.send({
type: 'promoter'
})
}
})
}
When I print headers on the server, it also does not have Authorization, showing:
headers: { host: 'localhost:5000',
connection: 'keep-alive',
pragma: 'no-cache',
'cache-control': 'no-cache',
accept: 'application/json',
'sec-fetch-dest': 'empty',
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.106 Safari/537.36',
'sec-fetch-site': 'same-site',
'sec-fetch-mode': 'no-cors',
referer: 'http://localhost:3000/admin',
'accept-encoding': 'gzip, deflate, br',
'accept-language': 'en-US,en;q=0.9,ru;q=0.8' }
What am I missing?
Another interesting issue is that when I run the request from Postman it shows 200 response code, and fastify prints 200 to the log. However, running from the saga/request with:
return fetch(url, newOptions)
.then(checkStatus)
.then(parseJSON)
I get response.status of 0 instead of 200 inside the request method, while the server log still shows "res":{"statusCode":200}.

I figured out what was the problem.
Apparently, my version of Chrome - Version 80.0.3987.106 (Official Build) (64-bit) and possibly other browsers and older versions of Chrome, as well, strip the authorization header, when it is used in conjunction with the no-cors mode. Enabling CORS and setting the appropriate headers solves the problem.

Try adding withCredentials: true and credentials: 'include' to your options:
options: {
mode: "no-cors",
withCredentials: true, // <-- ADD THIS
credentials: 'include', // <-- AND THIS
headers: {
Accept: "application/json",
Content-Type: "application/json",
Authorization: "Bearer NQ9xQLmYtq92aT8JHHRd7DGZJ..."
}
}
Reference: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials

Related

How to push request a CSRF Token in k6 performance testing tool - ReferenceError

I am quite new to k6 and load testing and I could not figure out why I am not able to push a token from one request to another, to test the login process in a Laravel-built web app. I hope somebody can help me out with this issue.
So my script looks like the following:
First request from where I want the token:
import { parseHTML } from 'k6/html';
import { sleep, group, check } from "k6";
import http from 'k6/http'
export const options = {}
export default function main() {
let response
group('page_1 - http://localhost:81/login', function () {
response = http.get('http://localhost:81/login', {
headers: {
host: 'localhost:81',
'user-agent':
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:104.0) Gecko/20100101 Firefox/104.0',
accept:
'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
'accept-language': 'en-US,en;q=0.5',
'accept-encoding': 'gzip, deflate, br',
connection: 'keep-alive',
cookie:
'XSRF-TOKEN=eyJpdiI6InY5ckZiaGdFTkI4Q0YyRi8rdmtyNUE9PSIsInZhbHVlIjoiT0NjZXlWWVBubTE5Zjh6cXBmNmZFWTdZKzBjVXlEOGhheGR0aVUybURSSGRZbEFmQ0N2RW5BQ3pOYzBQUXgweXhUaGNpRDhrcTV5SHBJUkEvU0FYTmN3eCswYTFsVnhQdk8wL1dkeHMvOTNXRTU4dnk2WjJ0QWFCSWdyQzEwQkwiLCJtYWMiOiIyODI1YmFkMDI1MzlkOGY4ODEyMDg4YWU5M2I5MWE3NmI3Yjg2ODczYTBkMzhhNmZiZTU5ODNlZDBjOGViNWIzIn0%3D; dev_session=eyJpdiI6ImNGalhPQW9GTWlYLzdsaEg1Qk0zdnc9PSIsInZhbHVlIjoiVU5jQ21OZmkyUDVnUmd2WUxUc3Z5dWhRbzBJTm1HWFhmQ1RuNzdFaEpRb1IzdVlIa1VhUkNXYTBlc2IxMHRMajl6UTAzYmFVTHZheEdTV2RrYU84d3pmdEUxYUlkaVFFT3J5YUVWSE1wVklRektqemVmbjhmK3hLWHo2ZmlMYlgiLCJtYWMiOiI3MTQ2ODg0Yjk4YjhhNjg2Yzg1YjllZjdmMWMyNzVkY2ZmNGM1NjAzYWUyN2NlMmE0ZjAwOTAyNWMwNGI2YmM2In0%3D',
'upgrade-insecure-requests': '1',
'sec-fetch-dest': 'document',
'sec-fetch-mode': 'navigate',
'sec-fetch-site': 'none',
'sec-fetch-user': '?1',
'sec-gpc': '1',
},
})
// Query the HTML for an input field named "_token".
const elem = response.html().find('input[name=_token]');
// Get the value of the attribute "value" and save it to a variable
const token = Elem.attr('value');
// Now you can concatenate this extracted value in subsequent requests that require it.
// console.log() works when executing k6 scripts locally and is handy for debugging purposes
console.log('The value of the hidden field is: ' + token);
check(response, {
list_OK: (r) => r.status === 200,
});
})
Second request - I want to use the token from the previous request to log in:
group('page_2 - http://localhost:81/customlogin', function () {
const url = 'http://localhost:81/customlogin';
const payload = JSON.stringify({
_token: `${token}`,
email: 'user',
password: '1234',
});
const params = {
headers: {
'Content-Type': 'application/json',
host: 'localhost:81',
'user-agent':
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:104.0) Gecko/20100101 Firefox/104.0',
accept:
'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
'accept-language': 'en-US,en;q=0.5',
'accept-encoding': 'gzip, deflate, br',
'content-type': 'application/x-www-form-urlencoded',
origin: 'http://localhost:81',
connection: 'keep-alive',
referer: 'http://localhost:81/login',
cookie:
'XSRF-TOKEN=eyJpdiI6ImlnZFZCUGF1b1FYUlJOdTJHNDd2Vnc9PSIsInZhbHVlIjoiTXhhdnZyQzlPamRFQ21rajdQVEZXcThzWittZndqU2d1L0hyN1BmRTA2a2RBbEpYZUhIUlRpWjh1RWJoQ1Y5dWJoTWVnaXEzZ1NVTjBndG1tenUyN2phY1lMdkIxSzBGek5aYndlSmRxaEhVTGY4WkNCcE1UY3N6YmowUnkrTkciLCJtYWMiOiJlNDIxNjhkYTc1NjYxNTVkNWZhOWViZDYwMGU1ODRkNmQ2ZGU0NjgyMjU5NjIxMzQ0MjYyYzRjMmJkYTVmNjUwIn0%3D; dev_session=eyJpdiI6IndxWXpobW9BUm1GSHNVZkorN0N0OGc9PSIsInZhbHVlIjoiSE82by9aRnBXQjFkNG5JMHFkVzUzc3kraUZOYUdIdjNlUGN6a3c2SjBSZy9TaVNxNmRsWnQzMTltMGt0MGQvWUoxQndyQXFvd2theWViNU94Z2FXaXlGTkc4ZVdERGY2KzRpUUZDZDIxNG85UFhhanRiajBCWElmcmthMWE0R3IiLCJtYWMiOiJjMDllMmRmNGJjNDRlMjM2MmZmZTViOWEwZmUzNWQ3MzNjZDI1NWQwYmU3MjE4OTZiMTRhN2U0NWNkMTcxMDAzIn0%3D',
'upgrade-insecure-requests': '1',
'sec-fetch-dest': 'document',
'sec-fetch-mode': 'navigate',
'sec-fetch-site': 'same-origin',
'sec-fetch-user': '?1',
'sec-gpc': '1',
},
};
response = http.post(url, payload, params);
console.log(response)
check(response, {
list_OK: (r) => r.status === 200,
});
})
After running the script I get an error message saying:
> ReferenceError: token is not defined
Thank you for your passionate help!
In this case you are defining a variable in the first call to group (const token ....` and then try to use it in the second call.
This has nothing to do with CSRF or k6, but with javascript ... and arguably scoping in most other languages.
But in order for both functions to see the same variable you will need to define it earlier - so for example next to your let response in the start of the default function.
Also remove const from the current definition as otherwise it won't work ;)

Symfony React Cors issue

I use Symfony 5 and React, with docker.
Both container are on different docker-compose but on the same newtork, so they can see and ping each other.
Now I want to POST something on one of my api route, here is my request:
const handleSubmit = async function (e) {
setError(null)
setLoading(true)
e.preventDefault()
const data = new FormData(e.target)
console.warn(data)
try {
const response = await fetch('https://localhost:8443/authentication_token', {
credentials: 'include',
headers: {
Accept: 'application/json',
},
method: 'POST',
body: data,
})
console.warn(response)
const responseData = await response.json()
console.warn(responseData)
onConnect(responseData)
} catch (e) {
setError(e)
setLoading(false)
}
}
Then I'm getting the following error:
Access to fetch at 'https://localhost:8443/authentication_token' from origin 'http://localhost:3001' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
So after some search I installed nelmio package to deal with cors, here is my nelmio_cors.yml file:
nelmio_cors:
defaults:
allow_credentials: true
allow_origin: ['*']
allow_methods: [ 'GET', 'OPTIONS', 'POST', 'PUT', 'PATCH', 'DELETE' ]
allow_headers: [ '*' ]
expose_headers: [ 'Authorization']
max_age: 0
hosts: []
origin_regex: true
forced_allow_origin_value: ~
paths:
'^/':
origin_regex: true
allow_origin: ['*']
allow_headers: [ '*' ]
allow_methods: [ 'POST', 'PUT', 'PATCH', 'GET', 'DELETE' ]
expose_headers: [ 'Link' ]
max_age: 3600
And added the below line in my .env:
###> nelmio/cors-bundle ###
CORS_ALLOW_ORIGIN=(.*)
###< nelmio/cors-bundle ###
And yet I get the same error and didn't manage to find an answer online.
Does anyone see what I've done wrong?
UPDATE
I've changed my nelmio_cors.yml config to the one above
And still got issues with cors but a different error message now:
Response {type: "cors", url: "https://localhost:8443/authentication_token", redirected: false, status: 404, ok: false, …}
It seems react don't manage to find the route. Any idea why ?
UPDATE 2
My nelmio_cors.yaml file now looks like that :
nelmio_cors:
paths:
'^/':
origin_regex: true
allow_origin: ['%env(CORS_ALLOW_ORIGIN)%']
allow_headers: ['*']
allow_methods: ['POST', 'PUT', 'PATCH', 'GET', 'DELETE']
max_age: 3600
.env contains:
CORS_ALLOW_ORIGIN=(.*)
But on the route call I receive the following error :
Access to fetch at 'https://localhost:8443/authentication_token' from origin 'http://localhost:3001' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Credentials' header in the response is '' which must be 'true' when the request's credentials mode is 'include'.
My response headers
access-control-allow-origin: http://localhost:3001
cache-control: no-cache, private
content-encoding: gzip
content-length: 451
content-type: application/json
date: Thu, 22 Oct 2020 08:12:11 GMT
server: openresty/1.17.8.2
status: 404
vary: Accept-Encoding
vary: Accept
x-debug-exception: Unable%20to%20find%20the%20controller%20for%20path%20%22%2Fauthentication_token%22.%20The%20route%20is%20wrongly%20configured.
x-debug-exception-file: %2Fsrv%2Fapi%2Fvendor%2Fsymfony%2Fhttp-kernel%2FHttpKernel.php:141
x-debug-token: 9b2891
x-debug-token-link: https://localhost:8443/_profiler/9b2891
x-powered-by: PHP/7.4.11
x-previous-debug-token: 486328
x-robots-tag: noindex
request header:
:authority: localhost:8443
:method: POST
:path: /authentication_token
:scheme: https
accept: application/json
accept-encoding: gzip, deflate, br
accept-language: fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7
content-length: 248
content-type: multipart/form-data; boundary=----WebKitFormBoundarywFASHmBarrNFyL7Y
cookie: pma_lang=fr; phpMyAdmin=a18f394d8e7daaefba20691da57c4b58; io=Jh7QElIlIXLDeAYaAAAA
origin: http://localhost:3001
referer: http://localhost:3001/
sec-fetch-dest: empty
sec-fetch-mode: cors
sec-fetch-site: cross-site
user-agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.99 Safari/537.36
I would suggest to have a different environmental variable value for local development and for your production or non-production environments.
nelmio_cors:
paths:
'^/':
origin_regex: true
allow_origin: ['%env(CORS_ALLOW_ORIGIN)%']
allow_headers: ['*']
allow_methods: ['POST', 'PUT', 'PATCH', 'GET', 'DELETE']
max_age: 3600
For local development you may have the following env.
CORS_ALLOW_ORIGIN=(.*)
For prod/non-prod you may want to list your web applications domains explicitly in order to be on a safe side.
CORS_ALLOW_ORIGIN=^https://(www\.)?(site.domain.com|site2.domain.com)$
For those who have the same issue, the problem came from the frontend
The data I recovered and place in body :
const response = await fetch(
'https://localhost:8443/authentication_token', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: data
})
were not well formated, and for some reason the backend sent back weird errors.
So I hardcoded them and this final result work :
const data = "{\"email\":\"test#test.com\",\"password\":\"test\"}";
const response = await fetch(
'https://localhost:8443/authentication_token', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: data
})

react -- Empty post body

I use react as my web's frontend, and go as my web's backend. My post sentences are:
fetch(MYURL, {
method: 'POST',
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'Origin, X-Requested-With, Content-Type, Accept',
'Content-Type': 'application/json',
'Accept': 'application/json',
},
mode: 'cors',
cache: 'default',
body: JSON.stringify(data),
})
But my backend program receives empty body.
My browser shows that the request payload is not empty, but when I use wireshark to capture the http packet, the content-length is 0 and the body is empty.

how to get form data params in headers using angularjs?

i using $http post After success i get the headers in network and it consist of the General,Request Headers,Response Headers,Form Data.
if i using headers() i got response headers but how i get the form data object.
$http({
method: "POST",
url: "http://localhost/demoPaymentGatway/index.html",
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'X-Requested-With': 'XMLHttpRequest'
}
}).success(function(data, status, headers, config) {
console.log(headers());
console.log();
}).error(function(r4) {
console.log(headers);
});
Headers:
General:
Request URL:http://localhost/demoPaymentGatway/index.html
Request Method:POST
Status Code:200 OK
Remote Address:[::1]:80
Response Headers:
Accept-Ranges:bytes
Connection:Keep-Alive
Content-Length:1856
Content-Type:text/html
Date:Sat, 06 Aug 2016 12:17:17 GMT
ETag:"740-5396528fb715b"
Keep-Alive:timeout=5, max=100
Last-Modified:Sat, 06 Aug 2016 11:05:25 GMT
Server:Apache/2.4.17 (Win32) OpenSSL/1.0.2d PHP/5.5.37
Request Headers:
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding:gzip, deflate
Accept-Language:en-US,en;q=0.8
Cache-Control:max-age=0
Connection:keep-alive
Content-Length:700
Content-Type:application/x-www-form-urlencoded
Cookie:PHPSESSID=el7a4qk56sv4ujo4kou0qf43k4
Host:localhost
Origin:null
Upgrade-Insecure-Requests:1
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36
Form Data:
mihpayid:114256656
mode:
status:failure
unmappedstatus:userCancelled
key:WHlKGc
txnid:264997125205
amount:1.0
addedon:2016-08-06 17:47:58
productinfo:productitem
firstname:vasu
please help me how to get this form data using $http,$resource
If you need to access the form data that was sent in the POST request in the success call back you need to look into the config.data property .
$http({
method: "POST",
url: "http://localhost/demoPaymentGatway/index.html",
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'X-Requested-With': 'XMLHttpRequest'
}
}).success(function(data, status, headers, config) {
//This is the post data that was originally sent
console.log(config.data);
}).error(function(r4) {
console.log(headers);
});
For reference please see this link

Why do my headers in TransformRequest become lowercase?

I have the following codes:
save: {
method: 'POST',
headers: {
'X-L5S-View-Mode': 'front',
'Content-Type': 'application/json',
'Accept-Language': ''
},
transformRequest: function (data, getHeaders) {
console.log(resource.lang);
var headers = getHeaders();
headers['Accept-Language'] = resource.lang;
console.log(headers);
return JSON.stringify(data);
}
}
in my resource factory.
Weirdly, all my headers are converted to lower case.
Here's the log:
fr <-- resource.lang
Object {x-l5s-view-mode: "front", content-type: "application/json", accept-language: "", accept: "application/json, text/plain, */*", Accept-Language: "fr"…} <-- headers
Why are my headers in lower case?
Plus, when I inspect with Chrome, I found that the Accept-Language is blank. So even I have changed the Accept-Language with headers['Accept-Language'] = resource.lang;, it doesn't work at all.
Because the latest version of Angular do not support this way to modify the headers anymore.
Angular 1.3.20 works for me.
Just change the version of Angular in bower.json, delete the original Angular, then cd to your directory and run bower install.

Resources