Cookies with CORS - node.js

I have a frontend running on AWS and a backend on Heroku. As such, users access a login page on AWS, make a request to login via the API on Heroku, and should get a cookie back with a session id. I have read all about CORS and even CORS + cookies, but still cannot successfully set a cookie through CORS (or at least I certainly cannot verify if I did via Chrome dev tools, and my Heroku app sure doesn't read any request header cookies). I am using fastify + fastify-cors + fastify-cookie
When running in dev environment, my frontend is https://localhost:3000 while the back is https://localhost:80
When I login, I should get back a cookie from the API # localhost:80. This is the response headers (ignore content length, I trimmed the session id for this question)
HTTP/1.1 200 OK
vary: Origin
access-control-allow-origin: https://localhost:3000
access-control-allow-credentials: true
set-cookie: session_id=66f9c629644b890fefaa9b4c58a10666; Max-Age=31536000; HttpOnly; Secure; SameSite=None
content-type: application/json; charset=utf-8
content-length: 587
Date: Tue, 02 Feb 2021 05:18:38 GMT
Connection: keep-alive
Keep-Alive: timeout=5
I followed this guide https://cors-errors.info/faq#cdc8
When I refresh the page, I should attempt to login via cookies. But my API at localhost:80 receives no cookies at all. This is what a login request via cookies looks like. Not sure if I should see some cookies being sent, but if I should, I presume they were never saved to the browser anyways.
POST /users/login/session HTTP/1.1
Host: localhost:80
Connection: keep-alive
Content-Length: 0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36
Accept: */*
Origin: https://localhost:3000
Sec-Fetch-Site: same-site
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: https://localhost:3000/
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Not sure what else to do at this point...

I believe adding path=/ and removing domain finally fixed everything.

Related

Node.JS Express - Original HTTP Request

Is there a way in Express to get the original HTTP request as it was prior to being parsed?
Like this:
GET / HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-GB,en;q=0.5
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
See link below for a basic implementation which I used to implement a store-and-forward proxy. This uses the raw Node.js http module, but express.js extends the req/res objects, so it should be fully compatible:
https://github.com/rkaw92/edi-broker-poc/blob/df7d643ed07e8004eb7a93fcde580549872fe757/src/httpUtils.ts#L50

How to allow set-cookie to be sent in AWS HTTP API Gateway?

Note: This question is not about AWS REST API Gateway, this question is about AWS HTTP API Gateway
My AWS HTTP API Gateway does not allow cookies to be passed.
I am using
express.js app on server hosted on ECS
Have set cors as follows:
On HTTP API Gateway:
On the express.js server I have configured cors in the following way:
In app.js
const cors = require("cors");
app.use(cors({
credentials: true
}));
The response to requests are sent in following way:
const options = {
maxAge: 900000,
httpOnly: true,
secure: true,
sameSite: 'none'
};
res.status(200)
.cookie("accessToken", accessToken, options)
.json({});
When I remove HTTP API Gateway from being in between client and server, the client is receiving cookies properly. But when calls are made to API Gateway, response is throwing following error:
**Access to fetch at 'https://api.*****.**/login' from origin 'https://cookie.*****.**' has been blocked by CORS policy: Request header field custom_field_name is not allowed by Access-Control-Allow-Headers in preflight response.**
^ How do I resolve this error?
Here is the preflight request and its response from developer console > network
GENERAL
Request URL: https://api.*****.**/login
Request Method: OPTIONS
Status Code: 204
Remote Address: [64:ff9b::306:a6f7]:443
Referrer Policy: strict-origin-when-cross-origin
RESPONSE HEADERS
access-control-allow-headers: *
Access-Control-Allow-Methods: GET, PUT, POST, DELETE, HEAD, OPTIONS
Access-Control-Allow-Origin: https://cookie.*****.**
access-control-max-age: 0
apigw-requestid: CIlgSiwhBcwEJyQ=
date: Thu, 08 Jul 2021 04:45:02 GMT
REQUEST HEADERS
:authority: api.*****.**
:method: OPTIONS
:path: /login
:scheme: https
accept: */*
accept-encoding: gzip, deflate, br
accept-language: en-US,en;q=0.9
access-control-request-headers: custom_field_name,content-type
access-control-request-method: POST
origin: https://cookie.*****.**
referer: https://cookie.*****.**/
sec-fetch-dest: empty
sec-fetch-mode: cors
sec-fetch-site: same-site
user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36
https://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-cors-console.html
Read point number 5 about Access-Control-Allow-Headers
That field has the list of allowed headers that you can pass through. You just need to add set-cookie to that list
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie

Redirect with basic auth to another website (in node)

How to redirect to another website with basic auth (in node)
Here is my code
const headers = {
Authorization: "Basic " +
new Buffer(USER + ":" + PASS).toString("base64")
};
ctx.response.set(headers);
ctx.response.redirect(URL)
The First Response return with basic auth
Authorization →Basic QWRxXxXxYWRtaW4=
Connection →keep-alive
Content-Length →111
Content-Type →text/html; charset=utf-8
Date →Fri, 15 Dec 2017 21:49:57 GMT
Location →http://localhost:8080/edit/data/P0000013
The following redirected GET request doesn't contain basic auth and got redirected again, to a log-in page.
# General
Request URL:http://localhost:8080/edit/data/P0000013
Request Method:GET
Status Code:302 Found
Remote Address:[::1]:8080
Referrer Policy:no-referrer-when-downgrade
# Request Header
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding:gzip, deflate, br
Accept-Language:en-US,en;q=0.9
Connection:keep-alive
Cookie:....
Host:localhost:8080
Upgrade-Insecure-Requests:1
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36
You can specify username & password as part of URL:
ctx.redirect('http://username:password#example.com');
You CANNOT redirect with attached headers (including basic auth), HTTP protocol doesn't support it.
But you can put your basic auth key/value pair in the new url as an argument:
HTTP/1.x 302 Found
Location: /api?auth=asdf
Or save it in cookies
HTTP/1.x 302 Found
Location: /api
Set-Cookie: auth=asdf

Express 401 redirect is not happening automatically

Encountering a situation where I redirect users with a 401 when they're not authorized to access a page. I have this in one of my routes:
res.redirect(401, '/login');
Seems simple enough, but the app loiters and doesn't redirect the user to /login. It just sits on a page similar to this:
Unauthorized. Redirecting to /login
Headers look fine too:
HTTP/1.1 401 Unauthorized
X-Powered-By: Express
Location: /login
Vary: Accept
Content-Type: text/html; charset=utf-8
Content-Length: 63
set-cookie: connect.sid=stuff; Path=/; HttpOnly
Date: Sun, 20 Nov 2016 02:20:07 GMT
Connection: keep-alive
The weird thing is that if I omit the status, the redirect happens normally:
res.redirect('/login'); // doesn't hang on page, redirect occurs immediately
I was under the impression that redirection would be automatic, but maybe not? Any insight?
401 is not a redirect status. Just use a regular (303) redirect instead – 401 is invalid if you’re not sending a WWW-Authenticate header anyway.

Image upload using curl

I want to upload image to remote site using curl cli version, i browse several pages here, but not able to solve my problem.
I log http header in firefox while uploading image:
https://www.site.xxx/upload_profile_picture/
POST /upload_profile_picture/ HTTP/1.1
Host: www.site.xxx
User-Agent: Mozilla/5.0 (Linux; U; Android 4.0.3; ko-kr; LG-L160L Build/IML74K) AppleWebkit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30
Accept: */*
Accept-Language: en-gb,en;q=0.5
Accept-Encoding: gzip, deflate
X-Requested-With: XMLHttpRequest
Content-Type: multipart/form-data; boundary=---------------------------124439777612656977621176581961
Cookie: 123
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
BELOW IS POSTDATA:::
-----------------------------124439777612656977621176581961
Content-Disposition: form-data; name="profile_pic"; filename="7eddaf78bbd055460167bae9eee3cdea.jpg"
Content-Type: image/jpeg
ÿØÿà
The basic curlsyntax would be
curl \
-F "image=#/yourPath/yourImageFile.jpg" \
'https://www.site.xxx/upload_profile_picture/'
Specify other POST data fields with one or several additional -F options if necessary, as in -F "username=xxx".
Or you could use Chrome, which will construct the cURL command for you in the inspector:

Resources