Missing authentication field in headers to store cookie expressjs - node.js

I'm trying to login with cookie JWT HTTPOnly, the problem is that the cookie comming with the response to the server, is comming in a field named 'cookie' and I would liked to have the cookie in a field named 'authorization' with a type 'Bearer' token. I'm using axios as client...
This is how the headers coming from my browser looks like...
{ host: 'localhost:8000',
connection: 'keep-alive',
accept: 'application/json, text/plain, */*',
origin: 'http://localhost:8080',
'user-agent':
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36',
referer: 'http://localhost:8080/allusers',
'accept-encoding': 'gzip, deflate, br',
'accept-language': 'pt-PT,pt;q=0.9,en-US;q=0.8,en;q=0.7',
cookie:
'jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVkNzE2ODI4NjE4ZjllMTQzYzY2NjIwNSIsImlhdCI6MTU2ODEwNzkxMSwiZXhwIjoxNTcwNjk5OTExfQ.cq85nqtLlw4npP53_3x-YxhXvapsm9qXKgOH0RCkLIM' }
this is how a send my cookie JWT
const token = jwt.sign({
id: user._id
},
process.env.JWT_SECRET, {
expiresIn: process.env.JWT_EXPIRES_IN
}
);
const cookieOptions = {
expires: new Date(
Date.now() + process.env.JWT_COOKIE_EXPIRES_IN * 24 * 60 *
60 * 1000
),
httpOnly: true
};
res.cookie('jwt', token, cookieOptions);

Instead of doing res.cookie('jwt', token, cookieOptions);
You could try using the standard response header.
You can set a header field to a value of your choosing:
res.set('Content-Type', 'text/plain');
Or set your own:
res.set(field, [value]);
I hope this helps!
Also maybe let the server make JWT keys in the future. That is how most people do it.
A good read is: The Hard Parts of JWT Security Nobody Talks About

Related

Decoding firebase id token failed, auth/argument error

I'm trying to authenticate using user requests and it appears that I'm it is failing even though I have the correct token (and in fact, from the decoded token, I can pull the uid, which I thought means it succeeded. On the client side, this is where my token is generated
const getIdToken = async() => {
if (firebaseAuth.currentUser) {
const token = await firebaseAuth.currentUser.getIdToken(true);
return token;
}
}
The tokens are added to headers in my axios requests
const header = await createHeader(userIdToken);
try {
await axios.post(SERVICE_PATH + '/gardens/addNew', garden, {headers: header})
via this functin
export const createHeader = async function(userIdToken) {
const payloadHeader = {
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${userIdToken}`,
},
};
return payloadHeader;
}
On the server-side, I decode
async function decodeIdToken(req, res, next) {
const header = req.headers?.authorization;
if (header !== 'Bearer null' && req.headers?.authorization?.startsWith('Bearer ')) {
const idToken = req.headers.authorization.split('Bearer ')[1];
admin
.auth()
.verifyIdToken(idToken)
.then(function (decodedToken) {
return next();
})
.catch(function (error) {
console.log(error);
return res.sendStatus(403);
});
} else {
res.sendStatus(401);
}
}
This is just in my server.js file (the last loaded middleware, after express, cors, and json)
app.use(decodeIdToken);
I've compared the tokens on the client and server and they appear correct. It even seems like the token is in fact decoded, since I can print the uid, but I may not be understanding that correctly. I'm very confused why I'm getting an argument error in particular.
After reviewing the headers, I've realized I confounded myself by having two separate requests with different formats. I'm posting both here, because both need to work, and I'm not seeing what I expected in the axios documentation on how to do this.
The first request takes this format:
await axios.post(SERVICE_PATH + '/gardens/addNew', garden, {headers: header})
And results in the following for req.headers on the server
{
host: 'localhost:5000',
connection: 'keep-alive',
'sec-ch-ua': '" Not;A Brand";v="99", "Microsoft Edge";v="97", "Chromium";v="97"',
accept: 'application/json, text/plain, */*',
authorization: 'Bearer undefined',
'sec-ch-ua-mobile': '?0',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36 Edg/97.0.1072.69',
'sec-ch-ua-platform': '"Windows"',
origin: 'http://localhost:3000',
'sec-fetch-site': 'same-site',
'sec-fetch-mode': 'cors',
'sec-fetch-dest': 'empty',
referer: 'http://localhost:3000/',
'accept-encoding': 'gzip, deflate, br',
'accept-language': 'en-US,en;q=0.9'
}
So it seems like the headers aren't going through, even though I explicitly added them the way I expected I should.
The second request type has no body, only params, so I pass the header as the second argument (which was what I was trying NOT to do, because I thought this was wrong, so I was phasing this out)
const res = await axios.get(SERVICE_PATH + '/plants/', header);
Which results in a header that looks the same as above, but with a defined token where it said undefined before. I don't believe it is throwing any firebase errors.
After seeing this, I think my question should actually have been, what is the right way to pass headers in an axios request? Should I be building them into the body if I need to pass additional objects? The examples I found largely seemed to have headers or a body rather than both, and the docs said to pass headers as the 3rd parameter (from my understanding), so now I'm confused :(
As it turns out, there were two problems I was running into. The first was not understanding how to properly send headers in axios (requiring the { headers } object containing key value pairs, not another object) and the second was not understanding how to properly set data into the header in my middleware. My updated code looks like
client (for requests with a body)
await axios.post(SERVICE_PATH + '/gardens/addNew', garden, { headers: header.headers})
And on the server I updated the try block for my token decoding to
admin
.auth()
.verifyIdToken(idToken)
.then(function (decodedToken) {
req['decodedToken'] = decodedToken;
return next();
})

node js express-session Set-Cookie on Postman/ Not in Flutter http headers

I'm facing an issue trying to connect an flutter application with my nodejs backend with express-session. In postman the response header includes a "Set-Cookie"-Header, but the flutter headers with http.post(...) do not: headers: {content-length: 113, content-type: application/json; charset=utf-8}.
I need a cookie to keep the authenticated session with passport. Any ideas how to fix it?
Flutter headers:
host: '127.0.0.1:3000', connection: 'keep-alive', 'content-length': '57', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.75 Safari/537.36', 'content-type': 'application/json; charset=utf-8', accept: '*/*', origin: 'http://localhost:51879', 'sec-fetch-site': 'cross-site', 'sec-fetch-mode': 'cors', 'sec-fetch-dest': 'empty', referer: 'http://localhost:51879/', 'accept-encoding': 'gzip, deflate, br', 'accept-language': 'de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7'
Postman Headers: 'content-type': 'application/json', accept: '*/*', 'postman-token': '7c79280d-****-****-a985-c01395e50e08', host: 'localhost:3000', 'accept-encoding': 'gzip, deflate, br', connection: 'keep-alive', 'content-length': '66'
Recommend you to use dio library for HTTP calls.
import 'package:dio/dio.dart';
class ApiProvider {
Dio _dio;
String aToken = '';
final BaseOptions options = new BaseOptions(
// base url to backend server
baseUrl: 'http://a.b.c.d:port/',
connectTimeout: 15000,
receiveTimeout: 13000,
);
static final ApiProvider _instance = ApiProvider._internal();
factory ApiProvider() => _instance;
ApiProvider._internal() {
_dio = Dio(options);
_dio.interceptors.add(InterceptorsWrapper(
onRequest:(Options options) async {
// to prevent other request enter this interceptor,
// use a new Dio(to avoid dead lock) instance to request token.
_dio.interceptors.requestLock.lock();
// set the cookie to headers
options.headers["cookie"] = aToken;
_dio.interceptors.requestLock.unlock();
return options; // continue
}
));
}
Future login() async {
final request = {
"userName": "",
"password": "",
"token": ""
};
final response = await _dio.post('/login', data: request, options: Options(
followRedirects: false,
validateStatus: (status) { return status < 500; }
));
//get cooking from response
final cookies = response.headers.map['set-cookie'];
if (cookies.isNotEmpty && cookies.length == 2) {
// it depends on how your server sending cookie
aToken = cookies[1].split(';')[0];
}
}
/// if we call this function without cookie then it will throw 500 err.
Future getSomething() async {
final response = await _dio.post('/something');
}
}

Node server unable to retrive the value of react axios request header parameter

I need to access axios header authorization token in server side(Node), showing undefined. Please help..
Client side(React) request:
var config = {
headers: {
'cache-control':'no-cache',
'content-type': 'application/x-www-form-urlencoded',
'authorization' :'bearer '+Auth.getToken()
}
};
axios.get(ApiConfig.API_BASE+'api/admin/profile/', config).then(function(response) {
this.setState({status:'success', profile: response.data.data});
}).catch(function(response) {
console.log(response);
});
Server side(Node):
module.exports = (req, res, next) => {
console.log(req.headers.authorization);
if(!req.headers.authorization) {
return res.status(401).end();
}
};
Log showing undefined. I also console the entire header, but their output is:
{ host: 'localhost:8027',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:55.0) Gecko/20100101 Firefox/55.0',
accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'accept-language': 'en-US,en;q=0.5',
'accept-encoding': 'gzip, deflate',
'access-control-request-method': 'GET',
'access-control-request-headers': 'authorization,cache-control',
origin: 'http://localhost:3001',
connection: 'keep-alive' }
How do I retrieve the authorization token value?
Thank you.
I'm assuming you are using express. If so, instead of getting the header value as req.headers.authorization, try req.get('authorization').
http://expressjs.com/en/api.html#req.get
If you are making a cross-origin HTTP request, please make sure CORS has been enabled in your server. If you are using express cors middleware can be used.
I guess your problem here is that since CORS has not been enabled, your server will receive a OPTIONS request first, so the entire header you console is from the OPTIONS request not the GET request as you desired. You can use console.log(req.method) to verify. BTW req.headers.authorization is ok to receive the header.

Aurelia http-client/http-fetch not sending headers

Tried multiple approaches to send custom-headers via Aurelia-http-client and Aurelia-Fetch-client to pass Headers in the get/post requests that I am making, but in the actual request, the headers are not being passed
approach 1
var client = new HttpClient()
client.createRequest('/api/information/save')
.asPost()
.withBaseUrl('http://10.0.0.13:3000')
.withHeader("X-auth-code", "abc")
.send()
approach 2
var client = new HttpClient()
.configure(x => {
x.withBaseUrl('http://10.0.0.13:3000');
x.withCredentials(true);
x.withHeader('Content-Type', 'application/json; charset=utf-8');
x.withHeader('x-client-code', 'abc');
});
Approach 3
this.http.configure(config => {
config
.withDefaults({
credentials: 'same-origin',
headers: {
"Content-Type": "application/json",
"x-client-code": "abc",
}
})
.useStandardConfiguration()
.withInterceptor({
request(request) {
request.headers.append("x-client-code","abc");
console.log(`${request.headers}`);
return request; // you can return a modified Request, or you can short-circuit the request by returning a Response
},
response(response) {
console.log(`Received ${response.status} ${response.url}`);
return response; // you can return a modified Response
}
});
})
But all of them lead to the same error
{ host: '10.0.0.13:3000',
connection: 'keep-alive',
'access-control-request-method': 'POST',
origin: 'http://localhost:9000',
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.104 Safari/537.36',
'access-control-request-headers': 'content-type',
accept: '*/*',
referer: 'http://localhost:9000/',
'accept-encoding': 'gzip, deflate',
'accept-language': 'en-GB,en-US;q=0.8,en;q=0.6' }
At the end we are unbable to pass the headers.
it's a security against cross-site scripting (and it's super annoying) #see : Cors Access-Control-Allow-Headers wildcard being ignored?

Set Express response headers before redirect

I'm implementing a site login that takes in an email/password combo, retrieves an API token, and returns it to the user to get stored (encrypted) in localStorage.
Currently, on successful POSTing to /login, the app redirects the user to the index page, with the token attached as a query, like so (as suggested here):
login.post('/', function(req, res) {
...checking password...
Auth.getToken(user, function(err, token) {
res.redirect('/?token=' + token);
});
});
This works fine, but I'd prefer to keep my URLs as clean as possible and set the token as a header instead:
login.post('/', function(req, res) {
...checking password...
Auth.getToken(user, function(err, token) {
res.set('x-access-token', token);
console.log(res._headers);
// --> {'x-powered-by': 'Express', 'x-access-token': <token>}
res.redirect('/');
});
});
console.log-ing res._headers shows that the headers are set as expected, but when I log req.headers on the request to the index page, it's not showing up:
{ host: 'localhost:3000',
connection: 'keep-alive',
'cache-control': 'max-age=0',
accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'upgrade-insecure-requests': '1',
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36',
referer: 'http://localhost:3000/login',
'accept-encoding': 'gzip, deflate, sdch',
'accept-language': 'en-US,en;q=0.8',
cookie: 'ifusr=crwj; _ga=GA1.1.1933420201.1409901705',
'if-none-match': '"1195161647"' }
Any suggestions appreciated!
Setting headers wouldn't work here because a redirect will execute a new http request, you can use express-session to store the auth token and fetch it when you need it
req.session.accessToken = token

Resources