I am trying to send the token in the headers of an HTTP request from backend to the frontend along with sending my own defined string. However, I am getting an issue. The token is being printed as null on the client-side. I don't know why:
Here's my code:
Node/Express
if (bcrypt.compareSync(passcode, results[0].password))
{
const token = jwt.sign({id: email}, secret, {expiresIn: 86400 });
console.log(token);
if(results[0].userrights == 'full')
{
res.setHeader('x-access-token', token);
res.send("Full Authorization");
}
//rest of the code
}
Angular
this.http.post('http://localhost:3000/api/login', form.value, {responseType: "text", observe:
'response'})
.subscribe(responseData => {
console.log(responseData);
console.log(responseData.headers.get('x-access-token')); //prints null on the console
I have searched quite a bit and found different examples which is making it very confusing. I don't want to use response status rather my own defined string. I have tried different things to print the variable but it still is throwing as null.
If you are using a browser extension to allow CORS requests then Access-Control-Expose-Headers should be added to the headers on server side. Please try adding the following line: res.setHeader('Access-Control-Expose-Headers', '*')
Angular2 's Http.post is not returning headers in the response of a POST method invocation
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers
Related
I'm new to web development and am currently stucked at a problem I can't solve easily. I'm using Django3.2.6, django restframework (DRF) 3.14, vue3.0 and axios (to make API calls). I wrote an APIView to lock a model while editing an it's instance:
class LockCmAPI(APIView):
def post(self, request, **kwargs):
obj = get_object_or_404(CM, id=self.kwargs['pk'])
obj.lock()
print('locking object')
return HttpResponse(status=status.HTTP_200_OK)
For the frontend I created a Vue app that calls periodically my LockCmAPI to lock the instance and prevent others from editing it:
let vue = Vue.createApp({
delimiters: ['[[', ']]'],
data: function(){
return{
current_cm: cm_obj,
intervall: null,
}
},
methods: {
lockCmHeartbeat(){
console.log('locking');
console.log(`${BACKEND_PATH+LOCK_PATH+this.current_cm.id}/`);
axios.post(`${BACKEND_PATH+LOCK_PATH+this.current_cm.id}/`, this.current_cm, {
xsrfCookieName: 'csrftoken',
})
.then((response) => {
console.log('lock');
console.log(response);
});
}
},
mounted() {
this.lockCmHeartbeat();
this.intervall = setInterval(function(){
this.lockCmHeartbeat();
}.bind(this), FIVE_SEC_IN_MILISEC);
},
beforeDestroy() {
clearInterval(this.interval);
}
});
vue.mount('#cm_vue_block');
After running my code I get a 403 response with the message "Request failed with status code 403". When I looked further into the response I got this "{\"detail\":\"CSRF Failed: CSRF token missing or incorrect.\"}" in my responseText.
My Question:
Why does it tell me I sent an incorrect csrftoken since it's the same csrftoken in the cookie named csrftoken?
Can someone clarify it for me?
How can I fix this problem?
THX :D
For everyone who is going to have the same problem. Since the csrftoken I provided is exactly the same as the csrftoken I saw in my cookie named csrftoken. It had to be another issue...After reading the django documentation https://docs.djangoproject.com/en/4.1/ref/settings/#std-setting-CSRF_HEADER_NAME :
Default: 'HTTP_X_CSRFTOKEN' The name of the request header used for
CSRF authentication.
As with other HTTP headers in request.META, the header name received
from the server is normalized by converting all characters to
uppercase, replacing any hyphens with underscores, and adding an
'HTTP_' prefix to the name. For example, if your client sends a
'X-XSRF-TOKEN' header, the setting should be 'HTTP_X_XSRF_TOKEN'.
I realized my csrf headername is named different to djangos default CSRF_HEADERNAME. In order to solve this problem I configured xsrfHeadername in my axios request, which looks like this:
axios.post(`${BACKEND_PATH + LOCK_PATH + this.current_cm.id}/`, this.current_cm, {
xsrfCookieName: 'csrftoken',
xsrfHeaderName: 'X-CSRFTOKEN',
})
I'm really struggling with a problem where every call I make to the #sendgrid/client comes back unauthorized. The exact same key can be used with #sendgrid/mail in the same code and it works fine.
I've tried everything but cannot get the NodeJS #sendgrid/client to work. I've even tried a brand new API Key and still get unauthorized.
I'm trying to use the /suppressions API. I can make the exact same call, with the same API key, in Postman and it works fine.
What am I doing wrong here?
Here is my code:
sgApiKey = config.get('sendGrid_APIKey');
sgClient.setApiKey(sgApiKey);
const email = "test#abc.com";
const headers = {
"on-behalf-of": "The subuser's username. This header generates the API call as if the subuser account was making the call."
};
const request = {
url: `/v3/asm/suppressions/global/${email}`,
method: 'GET',
headers: headers
}
sgClient.request(request)
.then(([response, body]) => {
console.log(response.statusCode);
console.log(response.body);
})
.catch(error => {
console.error(error);
});
I have tried creating a new API key with full permissions and it still does not work.
I'm expecting that my existing API key I already use for emailing should work to all the /suppression API.
I started to write some tests for my application and I have issues to read/get response from the server. I tried many things but nothing really worked, can someone help me please ?
// /api/checkCreds
exports.checkCreds = async function(req, res){
//validation
if(!await User.checkCreds(req.body.username, req.body.password)){
var result = {error: true, data: "Incorrect"}
res.sendStatus = 401;
return res.send(JSON.stringify(result));
}
If credentials sent to the server aren't matching, return a response with "Incorrect" message back to the user.
In the test I'm trying to get data from the server to check if properties are matching the expected output.
//test.js
it("We should fail with HTTP code 401 because incorrect data is passed (username='incorrect' password='incorrect')", function(done){
supertest(app)
.post('/api/checkCreds')
.send({username: 'incorrect', password: 'incorrect'})
.expect({error: true, data: "Incorrect"})
.expect(401, done);
});
When ran, test fails because expected properties are different from the response sent by the server, which is an empty object {}.
Any help is appreciated.
You may try changing your first expect to see if you can coax supertest into showing you the actual body that it's comparing to. For example, expect('')
If that doesn't work, there's a version of expect that accepts a function. In that function, you should be able to print out what you are getting in the response body, ie. console.log(res).
It may be that there's some confusion with the JSON return type-- I haven't used that directly. You could try expecting JSON.
Finally, there's a strange paragraph in the documentation that I don't think applies, but I thought I'd mention:
One thing to note with the above statement is that superagent now sends any HTTP error (anything other than a 2XX response code) to the callback as the first argument if you do not add a status code expect (i.e. .expect(302)).
While trying to fix my issue, I noticed that in the HTTP response, Content-Type header was set to text/plain and my server was returning JSON, so that probably was the thing that confused supertest.
I think that res.send() sets the header to text/plain by default and I had to manually set the header value to application/json by using res.type('json'). At that point I was able to read the response body without an issue.
I also learned that res.json() sets the Content-Type header to application/json by default, so you don't need to do it manually like with res.send().
Working code:
// /api/checkCreds
if(!await User.checkCreds(req.body.username, req.body.password)){
var result = {error: true, data: "Incorrect"}
return res.status(401).json(result);
}
//test.js
it("We should fail with HTTP code 401 because incorrect data is passed (username='incorrect' password='incorrect')", function(done){
supertest(app)
.post('/api/checkCreds')
.set('Content-type', 'application/json')
.send({username: 'incorrect', password: 'incorrect'})
.expect(401)
.expect(function(res){
console.log(res.body);
})
.end(done);
});
Feel free to correct me if I stated something that isn't quite right.
This is a function on my front-end that makes the request.
function postNewUser(){
fetch(`http://12.0.0.1:8080/users/test`, {
method: 'POST',
body: {nome: name, email: "test#test.com.br", idade: 20}
})
}
This is my back-end code to receive the request.
router.post('/users/:id', koaBody(), ctx => {
ctx.set('Access-Control-Allow-Origin', '*');
users.push(ctx.request.body)
ctx.status = 201
ctx.body = ctx.params
console.log(users)
})
For some unknown reason I receive nothing. Not even a single error message. The "console.log()" on the back-end is also not triggered, so my theory is that the problem is on the front-end.
Edit
As sugested by gnososphere, I tested with Postman, and it worked. So now i know the problem must be on the fron-end code.
You can try your backend functionality with Postman. It's a great service for testing.
the request would look something like this
If the problem is on the frontend, double check your fetch method by posting to a website that will return data and logging that in your app.
I'm learning how to build server with authentication. I'm following this tutorial, the final code can be found here. Which uses Express and JWT to build a simple login server. The following code:
app.use((req, res, next)=>{
// check header or url parameters or post parameters for token
console.log(req.body);
var token = req.body.token || req.query.token || req.headers['x-access-token'];
if(token){
console.log("token");
jwt.verify(token,"samplesecret",(err,decod)=>{
if(err){
res.status(403).json({
message:"Wrong Token"
});
}
else{
console.log("success");
req.decoded=decod;
next();
}
});
}
else{
res.status(403).json({
message:"No Token"
});
}
});
is adding a middleware, but I'm not sure what the purpose of this is and how it works. Is this being called on every route? What is req.body in this case? And what does res.status().json() do?
I also don't understand what the script auth and getlist under the HTML file does (too long to include). When are these scripts being called? Are they storing a cookie on the user's computer? What's being authenticated?
This is a lot of questions and I apologize. I'm quite new to web-dev, just want to figure out the fundaments. Thanks a bunch.
This is being called on every route to check for an existence of a token, decode, and check it.
If present, and decoded, (where it says console.log('success');) it is attaching the data decoded from the jwt to the request req so that in any of the controllers where you handle the request you can have the data (stored on req.decoded)
As far as res.status().json() (res of course meaning response)...
2 functions are being chained that are functions of res.
status(int)
json(obj)
req.status sets the response status code (eg 200 OK, 404 Not found, 503 Server error).
req.json send the response with the body being the json you pass in.
So the following would send the message {error:'We failed'} back to the client with a http status code of 503:
req.status(503).json({ error: 'We failed' });
You can read more about response methods/properties like this (and others like send, redirect, ect) on the Express documentation here.