I'm having a CORS related issue (I think), When I send a login post request from postman it succeeds. When I try logging in with my angular 2 front end app the request status seems to be 200, but nothing happens, and in the console I get this strange message that my localhost:4200 is not allowed, How can I fix this?
Angular http method
authenticateUser(user){
let headers = new Headers();
headers.append('Content-Type', 'application/json');
return this.http.post('http://localhost:3000/api/authenticate', user, {headers: headers})
.map(res => res.json());
}
Error msg from console.
Postman request (success)
In case it would be a express related problem here is my express code:
const express = require("express")
const bodyParser = require("body-parser")
const logger = require('morgan')
const api = require("./api/api")
const path = require('path')
const secret = require('./models/secrets')
const expressJWT = require('express-jwt')
const cors = require('cors');
const app = express()
app.set("json spaces", 2)
app.use(logger("dev"))
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({ extended: false }))
app.use(expressJWT({secret: secret}).unless({path : ['/api/authenticate', '/api/register']}))
app.use("/api/", api)
app.use(function (req, res, next) {
var err = new Error('Not Found')
err.status = 404
next(err)
})
app.use(function (err, req, res, next) {
console.error(err.status)
res.status(err.status || 500)
res.json({ msg: err.message, status: err.status })
})
// Body Parser middleware
app.use(bodyParser.json());
// CORS middleware
app.use(cors());
// set static folder
app.use(express.static(path.join(__dirname, 'public')));
//Call this to initialize mongoose
function initMongoose(dbConnection) {
require("./db/mongooseConnect")(dbConnection)
}
app.initMongoose = initMongoose
module.exports = app
And the route for /authenticate looks like this
// Authenticate
router.post('/authenticate', (req, res, next) => {
const username = req.body.username;
const password = req.body.password;
User.getUserByUsername(username, (err, user) => {
if (err) throw err;
if (!user) {
return res.json({ success: false, msg: 'User not found' });
}
User.comparePassword(password, user.password, (err, isMatch) => {
if (err) throw err;
if (isMatch) {
const token = jwt.sign({data: user}, secret, {
expiresIn: 604800 // 1 week
});
res.json({
success: true,
token: 'Bearer ' + token,
user: {
id: user._id,
name: user.name,
username: user.username,
email: user.email
}
});
} else {
return res.json({ success: false, msg: 'Wrong password' });
}
});
});
});
The CORS standard is a client-side standard, implemented in the browser. So it is the browser which prevent the call from completing and generates the error message - not the server. Postman does not implement the CORS restrictions, which is why you don't see the same error when making the same call from Postman.
Postman simply doesn't care about CORS headers. So CORS is just a browser concept and not a strong security mechanism. It allows you to restrict which other web apps may use your backend resources but that's all.
Note: The CORS error generally happens due to browser limitations regarding resources shared between different internet domains. Please refer to this blog post for more information about CORS and how the Postman Desktop Agent works.
The request that's being made is called a preflight request - You can see this in the error message, where it states that the response to the preflight request doesn't pass the access control check. Preflight requests are made by the browser, as CORS is a browser security restriction only - This is why it works in Postman, which is, of course, not a browser.
The docs for the CORS middleware you are using state the following:
To enable pre-flighting, you must add a new OPTIONS handler for the route you want to support:
In your case, as you've set up CORS handling to work for all origins, etc, you can use the following (again, from the docs):
app.options('*', cors()) // include before other routes
As the comment states, you'll need to move this up towards the top of your .js
file so that it is processed first.
It is also advisable to specifically set the allowed origins, routes, etc, in order to lock down which origins are able to access which endpoints. You can read more about that using your favourite search engine.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With