Firefox Can't Read Fetch Response Header - javascript

I'm trying to use the fetch API to send requests in my application, and if I get a 401 Unauthorized response, I want to read the value of the WWW-Authenticate response header. This works fine on Chrome, but on Firefox, I'm unable to see the WWW-Authenticate header, even though it's included in the Access-Control-Expose-Headers header of my response.
My code:
const api = async (endpoint, fetchOptions) => {
// fetchOptions:
// {
// "credentials": "same-origin",
// "method": "GET",
// "headers": {
// "Accept": "application/json",
// "Content-Type": "application/json"
// }
// }
const response = await fetch(endpoint, fetchOptions)
.catch(r => r)
.then(r => { r.headers.forEach(console.log.bind(console)); return r; });
// handle 401 errors
if (!response.status === 401 && response.headers.has('WWW-Authenticate')) {
const authenticate = response.headers.get('WWW-Authenticate');
const authEndpoint = authenticate.match(/authorization_endpoint="([^"]+)/i)[1];
window.location.href = authEndpoint;
return;
}
};
My request:
GET /api/login HTTP/1.1
Host: localhost:3001
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:67.0) Gecko/20100101 Firefox/67.0
Accept: application/json
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://localhost:3000/
Content-Type: application/json
Origin: http://localhost:3000
Connection: keep-alive
My response:
HTTP/1.1 401 Unauthorized
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json
Expires: -1
Server: Microsoft-IIS/10.0
Access-Control-Allow-Origin: http://localhost:3000
Access-Control-Expose-Headers: WWW-Authenticate
WWW-Authenticate: Bearer realm="http://localhost:3001", authorization_endpoint="<oauth endpoint>"
Bearer
X-SourceFiles: =?UTF-8?B?QzpcVXNlcnNcYXNjaW50ZXJuXFNvdXJjZVxSZXBvc1xQb3J0YWxcQVBJXFNhbXMuV2ViQXBpXGFwaVxsb2dpbg==?=
Date: Wed, 12 Jun 2019 13:37:08 GMT
Content-Length: 128
Console output:
no-cache cache-control
application/json content-type
-1 expires
no-cache pragma
Does anyone know why Firefox wouldn't be able to read that response header?

There's a known bug with multiple WWW-Authenticate response headers, you might be hitting that: https://bugzilla.mozilla.org/show_bug.cgi?id=1491010.

Related

Vue: Firebase Auth REST API throws 400 Bad Request Error

This is the error I'm getting:
POST
scheme
https
host
identitytoolkit.googleapis.com
filename
/v1/accounts:signUp
key
AIzaSyAk1ueCLjDDWCNrt_23o5A4RCfeaYIlN6k
Address
74.125.24.95:443
Status
400
Bad Request
VersionHTTP/3
Transferred850 B (198 B size)
Referrer Policystrict-origin-when-cross-origin
Request PriorityHighest
access-control-allow-origin
http://localhost:8080
access-control-expose-headers
date,vary,vary,vary,content-encoding,server,content-length
alt-svc
h3=":443"; ma=2592000,h3-29=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"
cache-control
no-cache, no-store, max-age=0, must-revalidate
content-encoding
gzip
content-length
129
content-type
application/json; charset=UTF-8
date
Mon, 24 Oct 2022 12:07:19 GMT
expires
Mon, 01 Jan 1990 00:00:00 GMT
pragma
no-cache
server
ESF
vary
Origin
vary
X-Origin
vary
Referer
x-content-type-options
nosniff
x-frame-options
SAMEORIGIN
x-xss-protection
0
Accept
*/*
Accept-Encoding
gzip, deflate, br
Accept-Language
en-US,en;q=0.5
Connection
keep-alive
Content-Length
79
Content-Type
text/plain;charset=UTF-8
Host
identitytoolkit.googleapis.com
Origin
http://localhost:8080
Referer
http://localhost:8080/
Sec-Fetch-Dest
empty
Sec-Fetch-Mode
cors
Sec-Fetch-Site
cross-site
TE
trailers
User-Agent
Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:106.0) Gecko/20100101 Firefox/106.0
This is part of the Vue JavaScript code I'm using:
async auth() {
let url =
'https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key= AIzaSyAk1ueCLjDDWCNrt_23o5A4RCfeaYIlN6k';
if (this.mode=="signup") {
url =
'https://identitytoolkit.googleapis.com/v1/accounts:signUp?key= AIzaSyAk1ueCLjDDWCNrt_23o5A4RCfeaYIlN6k';
}
const response = await fetch(url, {
method: 'POST',
body: JSON.stringify({
email: localStorage.getItem('email'),
password: localStorage.getItem('password'),
returnSecureToken: true
})
});
const responseData = await response.json();
if (!response.ok) {
const error = new Error(
responseData.message || 'Failed to authenticate. Check your login data.'
);
console.log(error);
throw error;
}
localStorage.setItem('token', responseData.idToken);
localStorage.setItem('userId', responseData.localId);
this.$store.state.token = localStorage.getItem('token');
this.$store.state.userId = localStorage.getItem('userId');
}
JSON.stringify is supposed to convert the object into a JSON string, but I'm not sure if this is where the problem is. I developed my code with help from:
https://firebase.google.com/docs/reference/rest/auth
Could someone tell me where did I go wrong?
I've resolved this issue. The problem arises simply from Firebase, where the user's sign-in password was shorter than 6 characters.

How can I use 'body-parser' in JavaScript?

I am studying Web server through Node.js.
When I try to use Body-parser, I can't progress anymore.
Status Codes are successful.
It seems to be successful. I got response message. But it doesn't show on browser.
What is the problem?
My code is below.
//basic-server.js
const express = require('express')
const cors = require('cors');
const app = express()
const bodyParser = require('body-parser')
const jsonParser = bodyParser.json()
const PORT = 5000;
const ip = 'localhost';
app.use(cors())
app.get('/', (req, res) =>{
res.send("hello")
})
app.post('/lower', jsonParser, (req, res) =>{
res.send(req.body.body.toLowerCase())
})
app.post('/upper', jsonParser, (req, res) =>{
res.send(req.body.body.toUpperCase())
})
app.listen(PORT, ip, () => {
console.log(`http server listen on ${ip}:${PORT}`);
});
// App.js
class App {
init() {
document
.querySelector('#to-upper-case')
.addEventListener('click', this.toUpperCase.bind(this));
document
.querySelector('#to-lower-case')
.addEventListener('click', this.toLowerCase.bind(this));
}
post(path, body) {
fetch(`http://localhost:5000/${path}`, {
method: 'POST',
body: JSON.stringify({body}),
headers: {
'Content-Type': 'application/json'
}
})
.then(res => {
return res.json()})
.then(res => {
this.render(res);
});
}
toLowerCase() {
const text = document.querySelector('.input-text').value;
this.post('lower', text);
}
toUpperCase() {
const text = document.querySelector('.input-text').value;
this.post('upper', text);
}
render(response) {
const resultWrapper = document.querySelector('#response-wrapper');
document.querySelector('.input-text').value = '';
resultWrapper.innerHTML = response;
}
}
const app = new App();
app.init();
The error message on console of developer tool
'Uncaught (in promise) SyntaxError: Unexpected token A in JSON at position 0
Promise.then (async)
post # App.js:21
toUpperCase # App.js:31'.
Below information is from network tab.
-preflight
Request URL: http://localhost:5000/upper
Request Method: OPTIONS
Status Code: 204 No Content
Remote Address: 127.0.0.1:5000
Referrer Policy: strict-origin-when-cross-origin
Access-Control-Allow-Headers: content-type
Access-Control-Allow-Methods: GET,HEAD,PUT,PATCH,POST,DELETE
Access-Control-Allow-Origin: *
Connection: keep-alive
Content-Length: 0
Date: Fri, 28 May 2021 10:15:31 GMT
Keep-Alive: timeout=5
Vary: Access-Control-Request-Headers
X-Powered-By: Express
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7
Access-Control-Request-Headers: content-type
Access-Control-Request-Method: POST
Cache-Control: no-cache
Connection: keep-alive
Host: localhost:5000
Origin: null
Pragma: no-cache
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/89.0.4389.128 Safari/537.36
-fetch
Request URL: http://localhost:5000/upper
Request Method: POST
Status Code: 200 OK
Remote Address: 127.0.0.1:5000
Referrer Policy: strict-origin-when-cross-origin
Access-Control-Allow-Origin: *
Connection: keep-alive
Content-Length: 1
Content-Type: text/html; charset=utf-8
Date: Fri, 28 May 2021 10:15:31 GMT
ETag: W/"1-bc1M4j2I4u6VaLpUbAB8Y9kTHBs"
Keep-Alive: timeout=5
X-Powered-By: Express
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7
Cache-Control: no-cache
Connection: keep-alive
Content-Length: 12
Content-Type: application/json
Host: localhost:5000
Origin: null
Pragma: no-cache
sec-ch-ua: "Google Chrome";v="89", "Chromium";v="89", ";Not A Brand";v="99"
sec-ch-ua-mobile: ?0
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/89.0.4389.128 Safari/537.36
{body: "a"}
body: "a"
-Response
A
You are using bodyparser correctly. The problem is in your code, you are returning just a symbol A, and the client trying to parse this that is incorrect JSON, that is why it fails.
You can change res.send(req.body.body.toUpperCase()) to res.send(JSON.stringify(req.body.body.toUpperCase())) to fix the problem.
the response you got is not a json format so try add this in your code above the requestes in server.js ;
app.use(bodyparser.urlencoded({extended: false}));
app.use(bodyparser.json());
if it workes then the problem that you are sending an other format not json so jason parser will not work .

CORS policy Issue, It works in local development, but it didn't work in deployed site

I'm having trouble with the CORS policy problem.
The project is very simple. I'm using the Sendgrid for sending e-mail.
I implemented frontend and backend for this tiny project. In backend, Sendgrid sending mail function is used.
I tested in local, it works fine. After I deployed the project, I got CORS issue.
This is the Error messages.
Access to fetch at 'https://mailsender-api.xxxxxx.xxx/sendmail' from origin 'https://mailsender-xxxxx.xxxxxx.xxx' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: 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.
POST https://mailsender-api.xxxxxx.xxx/sendmail net::ERR_FAILED
In frontend I separate fetch function
Fetch.tsx
export const fetchPost = async ({ endpoint, data }: any) => {
return fetch(`https://mailsender-api.xxxxxx.xxx/${endpoint}`, {
method: "POST",
body: JSON.stringify(data),
headers: {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*",
},
mode: "cors",
});
};
and different file calls the fetch function
const handleClick = async (
email: string,
subject: string,
intention: string
) => {
if (email === "" || intention === "") {
alert("Please fill out all fields");
} else if (!validateEmail(email)) {
alert("Invalid Email address");
} else {
const fetchOption = {
endpoint: `sendmail`,
data: {
email,
subject,
intention,
},
};
const result = await fetchPost(fetchOption);
if (result.ok) {
return history.push("/complete");
}
}
}
Below are backend code. I separate send mail function.
server.js
import cors from "cors";
import express from "express";
import { sendmail } from "./sendmail";
const router = express.Router();
const server = express();
server.use(
cors({
methods: ["GET", "POST", "OPTIONS"],
allowedHeaders: ["Content-Type", "Access-Control-Allow-Origin", "Accept"],
origin: "*",
credentials: true,
optionsSuccessStatus: 200, // some legacy browsers (IE11, various SmartTVs) choke on 204
})
);
server.use(express.json({ type: ["application/json"] })); // for parsing application/json
server.use(express.urlencoded({ extended: true })); // for parsing application/x-www-form-urlencoded
router.post("/sendmail", sendmail);
router.options("*", cors());
server.use(router);
server.listen(4000, function () {
console.log("app is listening");
});
export { router };
export default server;
when post requests comes in, sendmail function is invoked.
sendmail.js
import { sendScheduledMail } from "./config";
export const sendmail = async (req, res) => {
let data = {
address: req.body.email,
subject: req.body.subject,
content: req.body.intention,
};
try {
await sendScheduledMail(data.address, data.subject, data.content);
return res.end();
} catch (error) {
console.log(error);
}
};
Below is config.js file
import sgMail from "#sendgrid/mail";
import dotenv from "dotenv";
import "../.env";
dotenv.config();
export const sendScheduledMail = (address, subject, content) => {
let date = Math.round(new Date("June 29, 2020 12:37:00").getTime() / 1000);
let tempDate = Math.round(new Date().getTime() / 1000);
const email = {
from: "CBLM#CBLM.com",
to: address,
subject: subject,
html: `<p>${content}</p>`,
send_at: tempDate,
};
sgMail.setApiKey(process.env.SENDGRID_API_KEY);
return sgMail.send(email);
};
I deployed in Vercel.com. I asked about this problem, they said, it is codebase problem, so they have nothing to do. I searched for the solution, and I followed all they suggest, but it didn't work. Please help me.
------------------------UPDATED----------------------------------------
I deleted "Access-Control-Allow-Origin": "*", but it is not working.
I found out that Vercel has their own configure file ('now.json'). I added some headers, then I got something else.
now.json file
{
"routes": [
{
"headers": {
"Access-Control-Allow-Origin": "https://mailsender-delta.xxxxxx.xxx",
"Content-Type": "application/json",
"Access-Control-Allow-Methods": "POST, OPTIONS, HEAD",
"Access-Control-Allow-Headers": "Access-Control-Allow-Methods, Access-Control-Allow-Headers, Access-Control-Allow-Credentials, Access-Control-Allow-Origin, Content-Type",
"Access-Control-Allow-Credentials": "true"
},
"src": "/.*",
"dest": "/server.js"
}
]
}
I got POST https://mailsender-api.xxxxxx.xxx/sendmail net::ERR_ABORTED 405
Below is the request header
> General
Request URL: https://mailsender-api.xxxxxx.xxx/sendmail
Request Method: OPTIONS
Status Code: 204
Remote Address: 76.76.21.21:443
Referrer Policy: no-referrer-when-downgrade
> Response Headers
access-control-allow-credentials: true
access-control-allow-headers: Access-Control-Allow-Methods, Access-Control-Allow-Headers, Access-Control-Allow-Credentials, Access-Control-Allow-Origin, Content-Type
access-control-allow-methods: OPTIONS, GET, HEAD
access-control-allow-origin: *
cache-control: s-maxage=0
date: Fri, 03 Jul 2020 23:20:50 GMT
server: Vercel
status: 204
strict-transport-security: max-age=63072000; includeSubDomains; preload
x-vercel-cache: HIT
x-vercel-id: iad1::frndf-1593818450293-40ef1caa15b3
> Request Header
:authority: mailsender-api.xxxxxx.xxx
:method: OPTIONS
:path: /sendmail
:scheme: https
accept: */*
accept-encoding: gzip, deflate, br
accept-language: en-US,en;q=0.9,ko;q=0.8,la;q=0.7
access-control-request-headers: access-control-allow-credentials,access-control-allow-headers,access-control-allow-methods,content-type
access-control-request-method: POST
origin: https://mailsender-delta.vercel.app
referer: https://mailsender-delta.vercel.app/
sec-fetch-dest: empty
sec-fetch-mode: cors
sec-fetch-site: same-site
user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36
> General
Request URL: https://mailsender-api.xxxxxx.xxx/sendmail
Request Method: POST
Status Code: 405
Remote Address: 76.76.21.21:443
Referrer Policy: no-referrer-when-downgrade
> Response Headers
access-control-allow-credentials: true
access-control-allow-headers: Access-Control-Allow-Methods, Access-Control-Allow-Headers, Access-Control-Allow-Credentials, Access-Control-Allow-Origin, Content-Type
access-control-allow-methods: POST, OPTIONS, HEAD
access-control-allow-origin: https://mailsender-delta.vercel.app
cache-control: s-maxage=0
content-type: application/json
date: Fri, 03 Jul 2020 23:20:50 GMT
server: Vercel
status: 405
strict-transport-security: max-age=63072000; includeSubDomains; preload
x-vercel-cache: HIT
x-vercel-id: iad1::frndf-1593818450309-4f5547ab5464
> Request Headers
:authority: mailsender-api.xxxxxx.xxx
:method: POST
:path: /sendmail
:scheme: https
accept: */*
accept-encoding: gzip, deflate, br
accept-language: en-US,en;q=0.9,ko;q=0.8,la;q=0.7
access-control-allow-credentials: true
access-control-allow-headers: X-Requested-With, Content-Type, Accept
access-control-allow-methods: *
content-length: 88
content-type: application/json
origin: https://mailsender-delta.xxxxxx.xxx
referer: https://mailsender-delta.xxxxxx.xxx/
sec-fetch-dest: empty
sec-fetch-mode: cors
sec-fetch-site: same-site
user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36
I faced the same problem. The solution is available in the doc of vercel: https://vercel.com/support/articles/how-to-enable-cors .
In your node.js backend, create a file vercel.json and put the code there.
{
"headers": [
{
"source": "/api/(.*)",
"headers": [
{ "key": "Access-Control-Allow-Credentials", "value": "true" },
{ "key": "Access-Control-Allow-Origin", "value": "*" },
{ "key": "Access-Control-Allow-Methods", "value": "GET,OPTIONS,PATCH,DELETE,POST,PUT" },
{ "key": "Access-Control-Allow-Headers", "value": "X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version" }
]
}
]
}
It works for sure.

How to get the Content-Length header from a POST request send with axios?

I want to use the size and data of my POST request. I was doing some research and found out about the Content-Length header of a request, but I can't find it in my axios request headers.
I tried using interceptors, like that :
axios.interceptors.request.use(
config => {
console.log('config', config.headers);
if (config.url != `${API_URL}/login`)
config.headers.Authorization = 'Bearer ' + getAccessToken();
return config;
},
error => {
return Promise.reject(error);
}
);
And here is the response that I get:
Authorization: "Bearer [...access_token]"
Content-Type: "multipart/form-data"
common:
Accept: "application/json, text/plain, */*"
X-CSRF-TOKEN: "..."
X-Requested-With: "XMLHttpRequest"
__proto__: Object
delete: {}
get: {}
head: {}
patch: {Content-Type: "application/x-www-form-urlencoded"}
post: {Content-Type: "application/x-www-form-urlencoded"}
put: {Content-Type: "application/x-www-form-urlencoded"}
But in in Chrome this is what is shown:
Accept: application/json, text/plain
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9,ro;q=0.8,la;q=0.7
Authorization: Bearer [...access_token]
Connection: keep-alive
Content-Length: 5266672 <---- this is what I need
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryGMzak87LIZH05nme
Cookie: XSRF-TOKEN= ...
Host: ...
Origin: ...
Referer: ...
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36
X-CSRF-TOKEN: ...
X-Requested-With: XMLHttpRequest
X-XSRF-TOKEN: ...
Is there any way to make axios give me the content-length header? If not, is there any way to access it from anywhere else?
content-length will auto add by http adapter.

Ionic 3 $http.post return empty

I send a post with Ionic to php server. The server response a text plain but when a try get it, the object is empty.
var response = $http.post('https://somthing.com', $rootScope.data);
console.log(response);
return response;
Request headers:
Host: something.com
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0
Accept: application/json, text/plain, */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: http://localhost:8101/
Content-Type: application/x-www-form-urlencoded;charset=utf-8
Content-Length: 137
Origin: http://localhost:8101
Connection: keep-alive
Response headers:
HTTP/1.1 200 OK
Date: Tue, 23 Oct 2018 06:39:22 GMT
Server: Apache
Cache-Control: no-cache, private
Content-Encoding: gzip
Vary: Accept-Encoding,User-Agent
Cache-Control: max-age=2592000
Expires: Thu, 22 Nov 2018 06:39:21 GMT
Keep-Alive: timeout=3, max=500
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: text/html; charset=UTF-8
Hi can you use import { HTTP } from '#ionic-native/http';
example:
constructor(... public http: HTTP){}
var url = 'https://somthing.com';
var data = {'form': form};
var headers = {'Accept' : 'application/x-www-form-urlencoded',
'Content-Type' : 'application/x-www-form-urlencoded'};
this.http.post(url, data, headers).then((data) => {
#actions...
}, error => {
console.log(error);
#actions...
});

Categories

Resources