I am new to node.js. I need to use Json Web Tokens to authenticate my login requests.
In Postman and in the devtools, POST requests are working well : a new jwt is created for each request (seePOSTMAN, see DEVTOOLS
But, my authorization headers does not contain any jwt...
I got something like "Authorization : Bearer " (see AUTHORIZATION).
Here is my code :
**user.js/controllers
**
exports.login = (req, res, next) => {
User.findOne({ email: req.body.email })
.then(user => {
if(!user) {
return res.status(401).json({ message: 'Utilisateur non trouvé !'});
}
bcrypt.compare(req.body.password, user.password)
.then(valid => {
if(!valid) {
return res.status(401).json({ message: 'Mot de passe incorrect !'});
}
res.status(200).json({
userId: user._id,
token: jwt.sign(
{ userId: user._id},
'RANDOM_TOKEN_SECRET',
{ expiresIn: '24h' }
)
});
})
.catch(error => res.status(500).json({ error }));
})
.catch(error => res.status(500).json({ error }));
};
**app.js
**
app.use((req, res, next) => {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content, Accept, Content-Type, Authorization');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, PATCH, OPTIONS');
next();
});
How can I fix that ?
I'm running out of leads or solutions...
Thanks !
I am expecting to see the jwt appears just next to "Authorization: Bearer".
Related
I'm trying to redirect the user after the signup has been validated. See the code below, it never worked with everything i have tried. I also tried on the front end part with
<Redirect=to"/login" />
it wasn't a success either. I'm trying to redirect to : http://localhost:3000/login, the backend is currently on port 5000.
I also that those errors coming in the console :
Access to XMLHttpRequest at 'http://localhost:3000/login' (redirected from 'http://localhost:5000/users/signup') from origin 'http://localhost:3000' 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.
GET http://localhost:3000/login net::ERR_FAILED
createError.js:16 Uncaught (in promise) Error: Network Error
at createError (createError.js:16)
at XMLHttpRequest.handleError (xhr.js:99)
My first thought was that the header is not set, but it is in my app.js
app.use((req, res, next) => {
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader(
"Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content, Accept, Content-Type, Authorization"
);
res.setHeader(
"Access-Control-Allow-Methods",
"GET, POST, PUT, DELETE, PATCH, OPTIONS"
);
next();
});
Thanks in advance
exports.signup = (req, res) => {
bcrypt.hash(req.body.password, 10).then((hash) => {
const user = {
lastName: req.body.lastName,
firstName: req.body.firstName,
email: req.body.email,
password: hash,
};
User.create(user)
.then(() => {
res.redirect(301, 'http://localhost:3000/login');
})
.catch((error) => res.status(500).json({ message: "Impossible de créer l'utilisateur. " + error }));
});
};
res.status(200).redirect('login');
(EDIT) This will return 200 and redirect the user from the backend.
This is my solution from the front-end, if you'd like it.
On the frontend, you could redirect to your desired location using window.location.replace('/login') after the express returns a value.
What I mean by this is after you've validated the user on your Express API, return 200 via res.status(200).send() to let your front end know that this user is allowed to be redirected.
An example with jQuery:
Front-End
<script>
$.get('http://localhost:3000/login', function(data, status, jqXHR) {
if (status === 200) {
window.location.replace('redirect-location.html')
} else {
// What to do if the status isn't 200
}
})
</script>
Back-End:
app.get('/login', (res, req, err) => {
// Validate
const result = validatefunction() // true if login matches, false otherwise
if (result) {
res.status(200).send()
} else if (!result) {
res.status(400).send()
} else {
res.status(500).send()
}
})
Hope I've helped.
I have the following method on my frontend:
price.addEventListener("click", function() {
fetch("http://localhost:3000/payment", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
amount: {
currency: "EUR",
amount: "10.00"
},
description: "Description of the item to buy"
})
})
});
and the following is my Node.js server code:
const express = require('express');
const app = express();
app.listen(3000);
app.use(function (req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Credentials", "true");
res.header("Access-Control-Allow-Methods", "GET,HEAD,OPTIONS,POST,PUT");
res.header("Access-Control-Allow-Headers", "Access-Control-Allow-Headers, Origin,Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers");
next();
});
app.post("/payment", function (req, res) {
// console.log(req.body);
// console.log(req.method);
// console.log(req.headers);
client.payments.create({
amount: {
value: req.body.amount.amount,
currency: req.body.amount.currency
},
description: req.body.description,
})
.then(payment => {
// Forward the customer to the payment.getCheckoutUrl()
res.redirect(payment.getCheckoutUrl());
})
.catch(error => {
// Handle the error
console.log(error);
});
});
I do not get why my req.body returns undefined and I cannot access those values. When I click to buy an item from UI, in the console I get POST 500 (Internal Server Error) and it may be intuitive that this does not work and this might explain this. But I can see that req.method and req.headers have values and it seems they are working properly. What am I doing wrong?
I have a React application using axios as HTTP library, express server that uses http-proxy-middleware package and API express server that contains APIs.
React application should communicate with API server through proxy authentication server like this:
Within my React application I created this test method:
testReq(){
axios.get('http://localhost:5000/applicationData/checkMe', {
withCredentials: true,
headers: {
'x-access-token': '...'
}
})
.then(response => console.log(response.status))
.catch(e => console.log(e))
}
This is how my proxy method looks like:
server.use('/applicationData', authenticate, proxy({
target: 'http://localhost:4000',
changeOrigin: false,
onProxyReq(proxyReq, req) {
// proxyReq.setHeader('x-access-identity-email', req.decodedToken.email)
},
}))
and this is authenticate middleware function used above:
module.exports = (req, res, next) => {
const token = req.headers['x-access-token']
console.log('token', token)
if (token) {
verifyToken(token, global.config.secret).then((verificationResponse) => {
const { decoded, message } = verificationResponse
if (!decoded) return res.status(401).json({ message })
req.decoded = decoded
return next()
})
.catch((err) => {
console.error(err)
res.status(500).json({ message: 'Internal error' })
})
} else return res.status(401).json({ message: 'Missing authentication token' })
}
I enabled CORS on both API and Proxy servers like this:
server.all('/*', (req, res, next) => {
res.header('Access-Control-Allow-Origin', 'http://localhost:3000')
res.header('Access-Control-Allow-Headers', 'Access-Control-Allow-Headers': 'Origin, X-Requested-With, Content-Type, Accept, x-access-token')
res.header('Access-Control-Allow-Methods', 'PUT,POST,GET,DELETE,OPTIONS')
res.header('Access-Control-Allow-Credentials', 'true')
next()
})
The problem is that I get this response when request is sent:
I assume it's due to authentication middleware trying to access x-access-token header from OPTIONS request which doesn't exist and therefore returns 401. If I remove authentication middleware from proxy method then requests go through.
How do I make x-access-token present in OPTIONS requests? Or else, what is the proper way to handle this situation?
in facebook not allowing to paste code not sure, why, so pasting here:
in your middleware missing is (for options part as you have commented):
if (req.method == 'OPTIONS') {
res.send(200);
}
else {
next();
}
for error part, as you have said authentication triggering before cors part, so you may have to set that code before authentication (security part I am not much sure)
I think the line:
res.header('Access-Control-Allow-Headers', 'Access-Control-Allow-Headers': 'Origin, X-Requested-With, Content-Type, Accept, x-access-token')
should be:
res.header('Access-Control-Allow-Headers': 'Origin, X-Requested-With, Content-Type, Accept, x-access-token')
SOLVED, see my answer below
My server runs on localhost:3000
I develop on localhost:4200
I am creating something and trying to post it on an Amazon API
Angular side code:
sendSomething(something) {
const body = JSON.stringify(something);
// const headers = new Headers({'Content-Type': 'application/json'});
const headers = new Headers({'Access-Control-Allow-Origin': '*'});
return this.http.post('http://Amazon-API:port/send', body, {headers: headers})
.map((response: Response) => response.json())
.catch((error: Response) => {
this.error.handleError(error.json());
return Observable.throw(error.json());
});
}
Server side:
//////////////app.js//////////////
app.use(cors());
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", '*'); //<-- you can change this with a specific url like http://localhost:4200
// res.header("Access-Control-Allow-Credentials", true);
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
res.header("Access-Control-Allow-Headers", 'Origin,X-Requested-With,Content-Type,Accept,content-type,application/json');
next();
});
app.use('http://Amazon-API:port', engineRoutes);
//////////////routes/engine.js//////////////
router.post('/send', engine_controller.send_something);
//////////////controllers/engine.controller.js//////////////
exports.send_something = function (req, res, next) {
const somethingID = req.body.something;
Something.findById(somethingID, function(err, something) {
if (err) {
res.status(404).json({
title: 'Something not found',
error: {message: 'Something went wrong'}
});
}
console.log(something);
if (something) {
res.status(200).json({
message: 'Something successfully sent',
something: something
});
}
})
};
I have tried posting to that API with cors, without cors and with the res.headers appended, and every other variation I could think of
I still get this error which I've seen so common around here, but still, their solutions don't seem to work for me. Still getting this error...
Failed to load http://Amazon-API:port/send: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:4200' is therefore not allowed access. The response had HTTP status code 403.
That's from NETWORK tab:
Accept:*/*
Accept-Encoding:gzip, deflate
Accept-Language:he-IL,he;q=0.9,en-US;q=0.8,en;q=0.7
Access-Control-Request-Headers:access-control-allow-origin
Access-Control-Request-Method:POST
Connection:keep-alive
Host:Amazon-API:port
Origin:http://localhost:4200
Any kind of help would be so much appreciated
I see you added this code but I can't post comment yet, you may try to add this code before other routes
app.use(function (req, res, next) {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Headers', 'Origin, X-Requested-With,
Content-Type, Accept');
res.setHeader('Access-Control-Allow-Methods', 'POST, GET, PATCH, DELETE,
OPTIONS');
next();
});
Solved,
What I did was routing back to the server on the front:
sendSomething(something) {
const body = JSON.stringify(something);
const headers = new Headers({'Content-Type': 'application/json'});
return this.http.post('http://localhost:3000/api/somethings/send-something', body, {headers: headers})
.map((response: Response) => response.json())
.catch((error: Response) => {
this.error.handleError(error.json());
return Observable.throw(error.json());
});
}
And then accepting this route as it is on the back:
//////////////app.js//////////////////
app.use('/api/somethings/send-something', engineRoutes);
/////////////routes/engine.js/////////
router.post('/', engine_controller.send_something);
And most importantly, in the controller itself I used the newly downloaded request lib to send my json data to my external API:
////////////controlllers/engine.controller.js////////////
const request = require('request');
exports.send_something = function (req, res, next) {
const SomethingID = req.body.something;
Something.findById(SomethingID, function(err, something) {
if (err) {
res.status(404).json({
title: 'Something not found',
error: {message: 'Something went wrong'}
});
}
request({
url: app.get('amazon-API:port/method'),
method: "POST",
json: something
}, function (error, response, body) {
// console.log(error) <--- returns null or error
// console.log(response.statusCode <--- returns 200 / 403 / w.e
// console.log(body) <--- returns response pure html
res.status(200).json({
message: 'Something successfully sent',
response: body,
status: response.statusCode
});
});
})
};
Now as a response I'm getting what the server which I posted to sends me back, which is exactly what I need.
Ultimately I figured my way thanks to many other questions posted here
So thank you SOF once again!
Here is my get function in my message.service
message.service.ts
addMessage(message: Message) {
const body = JSON.stringify(message);
const headers = new Headers({ 'Content-Type': 'application/json' });
return this.http.post('http://localhost:3000/messages', body, { headers: headers })
.map((response: Response) => {
const result = response.json();
const message = new Message(result.obj.title, result.obj.content, 'Dummy', result.obj._id, null);
this.messages.push(message);
return message;
})
.catch((error: Response) => Observable.throw(error.json()));
}
And here is in my backend. If the user is not loggedin. It will return an error (Unauthorized).
routes/messages.js
router.use('/', (req, res, next) => {
jwt.verify(req.query.token, 'secret', (err, decoded) => {
if (err) {
return res.status(401).json({
title: 'Not Authenticated',
error: err
});
}
next();
});
});
And some posts says that it's related to CORS.
But I have this on my backend too.
app.js
app.use((req, res, next) => {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
res.setHeader('Access-Control-Allow-Methods', 'POST, GET, PATCH, DELETE, OPTIONS');
next();
});
app.use('/messages', messageRoutes);
app.use('/users', userRoutes);
app.use('/api', appRoutes);
And this is in my component.
message-input.component.ts
this.messageService.addMessage(message)
.subscribe(
data => this.snackBar.open('Your message is added!', 'Success!', {duration: 3000, extraClasses: ['success-snackbar']}),
error => console.error(error)
);
When there's an error because of authorization. The error is not the one I return from my backend. Instead it's this "Progress Event"
ProgressEvent {isTrusted: true, lengthComputable: false, loaded: 0, total: 0, type: "error", …}
I want to know how to show the error from my backend in json format. The error that should show to my console log.