How to save cookie on development localhost - express

I have node.js with express backend with some endpoints, all works fine testing with curl or postman, but on my client-side with angular on the http.post request i get the response correctly, but no cookie is saved.
I've tried changing my localhost dns, after some try i'm ended up using 127.0.0.1:4200 client and 127.0.0.1:3000 backend.
backend code:
const express = require('express');
const bodyParser = require('body-parser');
const webpush = require('web-push');
const cors = require('cors');
const cookieParser = require('cookie-parser');
const app = express();
app.use(cors());
app.use(bodyParser.json());
app.use(cookieParser());
app.post(path, /*here I call my function*/);
[...]
/*in my function i set cookie with these lines*/
res.cookie('userData',
{token: token,},{ httpOnly: true, secure: false }
);
client code:
[...]
constructor(private http: HttpClient) {}
[...]
/*request on my button click*/
this.http
.post<AuthResponse>(path, bodyReq)
who cares about these pieces of code, lets see the result.
in the response header i can see the set-cookie, and when i switch to the cookie tab of the request i can see it correctly, but..
something is telling chrome to don't save my cookie, he received it!!
I've already check on web about cors, domains, cookie settings.
Nothing works for me.
Thanks for any help.

the BENARD Patrick tips was right!!
To solve my problem add withCredentials both on client and server (using this solution I've had to specify the domain)
client code:
return this.http
.get<AuthResponse>(path, {
withCredentials: true,
headers: new HttpHeaders({
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': 'www.dns_to_127.0.0.1.com:4200',
}),
})
server code:
app.use(
cors({
origin: 'http://www.dns_to_127.0.0.1.com:4200',
credentials: true,
})
);
credentials: Configures the Access-Control-Allow-Credentials CORS header. Set to true to pass the header

Related

Browser fails to set cookies even with Set-Cookie response header

I am trying to get my Express backend to set a site-wide cookie on my NextJS frontend, each of which is running on separate virtual machines. The relevant backend and frontend configurations are:
In the frontend, I initate the following HTTP request:
fetch('http://192.168.1.<Express virtual machine>:3000/service', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({...}),
credentials: 'include'
}).then(res => res.json()).then(data => {console.log(data)});
In the backend, the following Express application is running with a global CORS middleware configured:
app.use(cors({origin: 'http://192.168.1.<Frontend virtual machine>:3000', credentials: true}));
app.post('/service', (req, res) => {
res.cookie('token', token, {
secure: false,
httpOnly: false,
sameSite: 'none'
});
res.json({...});
});
Upon initiating the HTTP request to /service, the Cookies section of my frontend application in the Storage (Firefox) or Application (Chrome) tab shows that there are no cookies set. However, in the network tab, the Cookies tab on my HTTP request shows that there is both a response cookie and a request cookie. The response cookie has path property set to '/' suggesting that it should have been set site-wide.

get CORS problem when ty to get a token in keycloak with vuejs and axios

I trying to access one keycloak with axios in my vuejs app, but I receive the cors error, can someone help me please? (If I make a post from POSTMAN to my keycloak works fine)
I using this code:
const params = new URLSearchParams();
params.append("grant_type", "password");
params.append("client_id", "notas-front");
params.append("username", usuario.value);
params.append("password", password.value);
console.log(params);
const config = {
// withCredentials: true,
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
};
axios.defaults.headers.common["Access-Control-Allow-Origin"] =
"http://localhost:8080";
axios
.post(
"http://localhost:8082/auth/realms/lumera/protocol/openid-connect/token",
params,
config
)
.then((response) => {
console.log(response);
});
and get this error:
but when I look the request I can't find the error:
the OPTIONS returns 200
but the POST dont
Postman doesn't care about Same Origin Policy, browser do. That's why your request is working in Postman but not in the browser.
Access-Control-Allow-Origin is a response header, you can't set it on the client request. And as you can see from the OPTIONS response headers your server is returning: Access-Control-Allow-Origin: http://localhost:8080
In a development environment the best way to solve this is setting a proxy in your vue configuration. Otherwise you should configure the server to allow requests from localhost:8080
Configure Web Origins properly in the Keycloak notas-front client config.

Cookies not stored with React native and Flask/ Flask jwt-extended

I am using Flask and flask-jwt-extended in order to do the authentication on my server.
When I use Postman, all my cookies are setup correctly. However, when I use a browser and react-native, none of the cookies are stored.
Environment:
Flask Backend: 127.0.0.1:5000
React-Native Front: 127.0.0.1:19006
Here is my Flask config:
JWT_SECRET_KEY = os.getenv("JWT_SECRET_KEY", 'local-secret')
JWT_TOKEN_LOCATION = ['cookies']
JWT_ACCESS_TOKEN_EXPIRES = datetime.timedelta(seconds=1800)
JWT_COOKIE_SECURE = False
CORS_HEADERS = "Content-Type"
JWT_REFRESH_TOKEN_EXPIRES = datetime.timedelta(days=15)
JWT_COOKIE_CSRF_PROTECT = True # set_refresh_cookies() will now also set the non-httponly CSRF cookies
JWT_CSRF_CHECK_FORM = True
JWT_ACCESS_CSRF_HEADER_NAME = "X-CSRF-TOKEN-ACCESS"
JWT_REFRESH_CSRF_HEADER_NAME = "X-CSRF-TOKEN-REFRESH"
SSL_REDIRECT = False
jwt = JWTManager()
app = Flask(__name__)
app.config.from_object(APP_CONFIG[CONFIG_ENV])
cors = CORS(app, resources={r"/*": {"origins": "http://127.0.0.1:19006"}}, supports_credentials=True)
APP_CONFIG[CONFIG_ENV].init_app(app)
jwt.init_app(app)
Here is how I store cookies (classic, and working with postman):
access_token = create_access_token(identity = token_identity)
refresh_token = create_refresh_token(identity = token_identity)
resp = jsonify({"access_token": access_token, "refresh_token": refresh_token})
set_access_cookies(resp, access_token)
set_refresh_cookies(resp, refresh_token)
However, whenever I am using the browser (127.0.0.1:19006) with react-native to make requests, cookies are never stored.
Any ideas where the problem can come from?
After many hours of struggle, the solution was simpler than I thought:
In the front code (react-native), I had to add:
credentials: "include"
in my fetch requests.
See: https://developers.google.com/web/updates/2015/03/introduction-to-fetch
You are likely running into a web browser security mechanism called the same origin policy, where it is treating those two urls and two different domains and thus not saving the cookies. You could use a webpack proxy/apache/nginx to serve both the api and the frontend from the same domain, or possibly look into a CORS setting to allow this setup to work.
I also had this problem. This is what I did:
Front-end:
Add credentials: "include" when doing fetch requests:
fetch(domain + "/createAccount", {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
credentials: 'include',
body: JSON.stringify(inputData),
})
.....
Backend:
Ensure that you set Access-Control-Allow-Origin to your url http://localhost:3000, Access-Control-Allow-Credentials to True and samesite to None and secure to True.
resp = Response(
.......
)
resp.headers.add('Access-Control-Allow-Origin', 'http://localhost:3000')
resp.headers.add('Access-Control-Allow-Credentials', 'true')
resp.set_cookie('token', value=encoded_jwt, httponly= True, expires = TOKEN_EXPIRY_DATE, samesite='None', secure=True)

How to solve CORS policy issue in a fullstack app [duplicate]

This question already has an answer here:
CORS Error: “requests are only supported for protocol schemes: http…” etc
(1 answer)
Closed 3 years ago.
I am building a MEVN-stack app, but I fail to make a request from my fron-end to the server due to Cross origin policies. I have enabled the cors middleware for all routes, but it does not take effect. I also tried applying it on each route individually and to specify the origin, but still no effect.
index.js:
const express = require('express')
const cors = require('cors')
const mongoose = require('mongoose')
const BanksController = require('./controllers/BanksController')
const OfficesController = require('./controllers/OfficesController')
const PORT = process.env.PORT || 3000
mongoose.connect(process.env.DB, { useNewUrlParser: true, useUnifiedTopology: true });
const app = express()
app.use(cors({ origin: 'http://localhost:3001' }))
app.get('/api/banks', BanksController.index)
app.get('/api/offices', OfficesController.index)
app.listen(PORT, () => console.log('Listening on port ' + PORT))
the ajax request:
axios.get('localhost:3000/api/banks')
.then(res => console.log(res))
.catch(err => console.log(err))
Try changing this:
axios.get('localhost:3000/api/banks')
to this:
axios.get('http://localhost:3000/api/banks')
Notice how the error message complains about the protocol scheme.
The problem is not your server. The problem is that using localhost:3000 treats localhost: as a scheme. The 'scheme' is the bit of the URL before the first colon.
You won't even see the request in the Network section of the developer tools because the browser doesn't know how to make a localhost: 'request'.
Try to add:
app.use(cors({ origin: 'http://localhost:3001/*' }))
It will be enabled for all routes. Or just use:
app.use(cors())
app.options('*', cors());

body-parser does not work, req.body is undefined [duplicate]

I can't seem to recover the form-data of a post request sent to my Node.js server. I've put below the server code and the post request (sent using postman in chrome):
Post request
POST /api/login HTTP/1.1
Host: localhost:8080
Cache-Control: no-cache
----WebKitFormBoundaryE19zNvXGzXaLvS5C
Content-Disposition: form-data; name="userName"
jem
----WebKitFormBoundaryE19zNvXGzXaLvS5C
NodeJS server code
var express = require('express'); // call express
var app = express(); // define our app using express
var bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(bodyParser());
app.all('/*', function(req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', 'Content-Type,accept,access_token,X-Requested-With');
next();
});
var port = process.env.PORT || 8080; // set our port
var router = express.Router(); // get an instance of the express Router
router.get('/', function(req, res) {
res.json({ message: 'I am groot!' });
});
// Login
router.route('/login')
.post(function(req, res){
console.log('Auth request recieved');
// Get the user name
var user = req.body.userName;
var aToken = getToken(user);
res.json({
'token':'a_token'
});
});
app.use('/api', router);
app.listen(port);
The login method tries to obtain the req.body.userName, however, req.body is always empty.
I've seen other cases on SO describing such behavior but none of the related answers did apply here.
Thanks for helping out.
In general, an express app needs to specify the appropriate body-parser middleware in order for req.body to contain the body.
[EDITED]
If you required parsing of url-encoded (non-multipart) form data, as well as JSON, try adding:
// Put this statement near the top of your module
var bodyParser = require('body-parser');
// Put these statements before you define any routes.
app.use(bodyParser.urlencoded());
app.use(bodyParser.json());
First, you'll need to add body-parser to the dependencies property of your package.json, and then perform a npm update.
To handle multi-part form data, the bodyParser.urlencoded() body parser will not work. See the suggested modules here for parsing multipart bodies.
I followed this
https://www.tutorialspoint.com/expressjs/expressjs_form_data.htm
var bodyParser = require('body-parser');
var multer = require('multer');
var forms = multer();
// apply them
app.use(bodyParser.json());
app.use(forms.array());
app.use(bodyParser.urlencoded({ extended: true }));
// how to use
router.post('/', function(req, res) {
console.log(req.body);
console.log('received the widget request');
});
To handle multipart/form-data request that support file upload, you need to use multer module. npm link for multer middleware
For Json: Use body-parser.
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({extended: true}))
(you should Also send Content-Type: application/json in request header)
For Normal Form, Or multipart form (form with files), Use body-parser + multer.
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({extended: true}))
app.use(multer().array())
(You should NOT send Content-Type: application/json in this case. you should send nothing, or Content-Type: multipart/form-data if you have files in form.
in postman you should not send Content-Type: multipart/form-data manually. otherwise you'll get an error (Boundary not found). (it will add this automatically.).)
Make sure to put in this order:
bodyParser.json() first.
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
Make sure you are not sing enctype as multipart/form-data, body parser does not support it.
use below line before you define any route.
app.use(bodyParser.urlencoded());
app.use(bodyParser.json());