How to set headers while requesting a page in nodejs? - javascript

I saw many tutorials on jwt authentication but every video maker uses Postman to show what's happening and they pass on the header in the headers section while requesting a URL in Postman. I tried to do it with JavaScript but I was not able to do it.
I want to do jwt authentication but after token generation, I send it to client side to use it for further requests but I failed to do so after trying it a few times. I also tried to set req.headers in server side but it didn't do what I wanted to..
I want to set request headers for authentication of the form "Bearer {token}" for every request after token generation. How to do it with JS??
What I am most concerned about is that every tutorial does it with postman but they didn't show how they implemented it in their own app. I hope my question is clear.

You can easily add header on your http request like that
it has been solved here Node.JS: How to send headers with form data using request module

In vanilla nodejs:
const uri = "http://example.com";
const options = {
headers: {
"Authorization": "Bearer ...."
}
}
// require http/https lib
let req = require("http").request(uri, options, (res) => {
const chunks = [];
res.on("data", function (chunk) {
chunks.push(chunk);
});
res.once("end", () => {
// concat body chunks
let body = Buffer.concat(chunks);
console.log(body.toString());
});
});
req.on("error", (err) => {
console.log(err);
});
req.end();
https://nodejs.org/dist/latest-v12.x/docs/api/http.html#http_http_request_options_callback

Something like that:
$.ajax({
url: url,
beforeSend: function(xhr) {
xhr.setRequestHeader("custom_header", "value");
},
success: function(data) {
}
});

First install jwt and express framework using npm then make a middleware file which will check if the tokek is set or not.
Middleware.js :
let jwt = require('jsonwebtoken');
const config = require('./config.js');
let checkToken = (req, res, next) => {
let token = req.headers['authorization']; // Express headers are auto converted to lowercase
if (token) {
if (token.startsWith('Bearer ')) { // Checks if it contains Bearer
// Remove Bearer from string
token = token.slice(7, token.length); //Separate Bearer and get token
}
jwt.verify(token, config.secret, (err, decoded) => { //Inser the token and verify it.
if (err) {
return res.json({
status: false,
message: 'Token is not valid'
});
} else {
req.decoded = decoded;
next();
}
});
} else {
return res.json({
status: false,
message: 'Access denied! No token provided.'
});
}
};
Next, create a config file which will contain the secrets.
Config js:
module.exports = {
secret: 'worldisfullofdevelopers'
};
Finally, create a token route which will create your token and after that the rest of the calls will be authenticated for that token.
Index.js :
const middleware = require('./middleware');
const jwt = require("jsonwebtoken");
const config = require('./config.js');
//Call token Route
app.use('/token', (req, res, next) => {
//Generate Token
let token = jwt.sign({ username: "test" },
config.secret,
{
expiresIn: '1h' // expires in 1 hours
}
);
//Send Token
res.json({
success: true,
message: 'Authentication successful!',
token: token
});
});
//Add Authentication to all routes
app.use(middleware.checkToken);
//===> All the routes after middleware will be checked for token
app.use('/getUser', (req, res, next) => {;
console.log('do something')
});

If I understand correctly, you want to set the HTTP header on the client, in order to pass an authentication token to the server. I would recommend that you use a library like **axios*.
Using axios, once you receive the toke, set the header for every outgoing communication with the following line of code:
axios.defaults.headers.common['Authorization'] = "Bearer " + token;
This will set the authentication http header to the form you need.

Related

How to pass file(Image) via NextJS API Routes to external API?

I use NextJS (combined: SSR and SPA for authorized dashboard) with Django Rest FW on the backend. For auth I use JWT token, which is stored in cookies. For that reason, I need a middleware at /pages/api/* for each request to append from cookie access token.
Question:
How to implement a protected request to send file to /pages/api/upload and send it to DRF with an access token?
Sample of small API middleware
export default async (req, res) => {
const { id } = req.query
const cookies = cookie.parse(req.headers.cookie ?? "");
const access = cookies["access"] ?? false;
if (access === false) {
return res.status(401).json({
error: "User unauthorized to make this request"
});
}
if (req.method === "GET") {
try {
const apiRes = await fetch(`${LOCAL_API_URL}/items/${id}`, {
headers: {
"Accept": "application/json",
"Content-Type": "application/json",
"Authorization": `Bearer ${access}`
}
});
const data = await apiRes.json();
if (apiRes.status === 200) {
return res.status(200).json(data);
} else {
return res.status(apiRes.status).json({
error: data.error
});
}
} catch(err) {
console.log(err);
return res.status(500).json({
error: "Something went wrong"
});
}
} else
res.setHeader("Allow", ["GET"]);
return res.status(405).json({
error: `Method ${res.method} is not allowed`
});
}
For sending image you should use FormData.
Firstly create an instance of FormData.
const formData = new FormData()
Then, you can add image into that.
formData.append('fieldName', someFileInput.current.files[0])
Also, if you want to add some more data with the image, you can append it to FormData too, the similar way.
formData.append('fieldName', someMoreData)
Then, you should set Content-Type to 'multipart/form-data', this is to server understand you pass the FormData.
And, finally, send the form data via Fetch.
I was glad to answer you, I hope it helps you!
the solution was raiser simple. Just passed everything I received and appended token to headers/
export default async (req, res) => {
// all extra validation
const apiRes = await fetch(`${LOCAL_API_URL}/upload/`, {
method: "POST",
headers: { ...req.headers, ...{ "Authorization": `Bearer ${access}` } },
body: req.body
});
// all extra validation
}

Is it possible to pass a request header on a link with EJS template? Express/Node.js

I'm a trying to make a route accessible only if you are authenticated with JWT using below middleware but I can't seem to find a way to pass the token in the get request from client side ?
It works fine on postman and I if using a fetch from client side it won't redirect me to the page I want to go
auth.js
async function (req, res, next) {
const token = req.header('x-auth-token');
if (!token) {
return res.status(401).json({ msg: 'Forbidden' });
}
try {
const decoded = jwt.verify(token, process.env.TOKEN_SECRET);
req.user = decoded.user;
next();
} catch (e) {
return res.status(401).json({ err: 'fail' });
}
};
server side
router.get('/', auth, function (req, res, next) {
res.render('pages/person');
});
You can simply attach your token to the headers in the request and sent it with get or even 'delete` method.
for example, in the fetch method you can attach your token in this way in your client side:
fetch('URL_GOES_HERE', {
method: 'post',
headers: new Headers({
'Authorization': YOUR_TOKEN,
'Content-Type': 'application/x-www-form-urlencoded'
}),
});
Now, you can retrieve the token in the node app:
const token = req.headers.authorization || "";

PostMan Pre-request script for fetching JWT using Laravel

I am trying to write a pre-request script for getting JWT for my postman tests using Laravel. I tried the js code that works perfect when I use .NET REST API, but now in Laravel it is not working. If I hit the login endpoint it works I got my JWT, and the response look like this:
{
"status_code": 200,
"access_token": "15|we59pMz1wA6TqwALTJg9IT8pNs3mc4Omwibm7Lkd",
"token_type": "Bearer"
}
Here is my pre-request JS script:
const requestBody =
{
"Email" : "username",
"Password" : "password"
}
pm.sendRequest
({
url: 'http://localhost:8000/api/login',
method: 'POST',
header:
{
'content-type': 'application/json'
},
body:
{
mode: 'raw',
raw: requestBody
}
}, function (err, res)
{
if(err)
{
console.log("Login failed:");
console.log(JSON.stringify(err));
return;
}
else
{
const response = res.json();
const token = 'Bearer ' + response.access_token;
pm.environment.set("TOKEN", token);
console.log("Login succeeded!");
}
});
The response in pre-request is this:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta http-equiv="refresh" content="0;url='http://localhost:8000'" />
<title>Redirecting to http://localhost:8000</title>
</head>
<body>
Redirecting to http://localhost:8000.
</body>
</html>
Your token doesn't seem like a JWT.
This is not base64 and does not contain the 3 parts: header, payload, signature.
Don't hesitate to look at my Postman pre request gist for JWT there are some explanations here too.
It contains one function to check the token validity:
/** Checks if the JWT is present and not expired
The token is expected to be found in `token` environment variable
*/
function isValidToken() {
const token = pm.environment.get("token");
if (!token) {
console.log("Token is missing");
return false;
}
// Payload is retrieved by
// JSON parsing the base64 decoded `atob()` 2nd part of the JWT `[1]`
// (1st is the header, 3rd is the signature)
const payload = JSON.parse(atob(token.split('.')[1]));
// Expiration timestamp (in seconds) is located in the `exp` key
const millisecBeforeExpiration = (payload.exp * 1000) - (new Date()).getTime();
if (millisecBeforeExpiration <= 0) {
console.log("Token is expired");
return false;
}
console.log("Token is valid",
`will expire in ${millisecBeforeExpiration / 1000} seconds`);
return true;
}
and one to get a new token
/** Gets a new JWT
This can be entirely custom authentication.
Here we rely on `user`/`pass` environment variables.
`host` also needs to be set, feel free to use another route instead of /give-me-a-jwt :)
*/
function login() {
const body = JSON.stringify({
"user": pm.collectionVariables.get("user"),
"pass": pm.collectionVariables.get("pass")
});
const request = {
url: pm.collectionVariables.get("host") + "/give-me-a-jwt",
method: "POST",
header: {
"Content-Type": "application/json",
"Accept": "application/json",
},
body,
};
pm.sendRequest(request, (err, res) => {
if (res.code !== 200) throw new Error(res.status);
console.log("Token refreshed");
pm.environment.set("token", res.json().token);
});
}
Now you can just get a new token if not valid:
if (!isValidToken()) login();
Of course don't forget to use your brand new token in your Postman's Bearer Token authentication type

Ajax request cors and cookies steps

I have a client front end at localhost:1841 and a back end at localhost:9000.
My authentication system use a simple couple username/password that delivers a Json Web Token(jwt).
When my client receives the token, i ask him to save it in the cookie with javascript. But when i make XmlhttpRequest call from my client (:1841) to my server (:9000), there is no cookies in the request. So my server delivers a 401 (behavior is ok).
I know that is normal, none information from the cookies is sent because of the SAME-ORIGIN-POLICY.
I m using extjs 6 as client and node js as server.
What are all the steps to configure in the server side and client side to make this working ?
In server side i have already authorize cors request.
I have heard of httpOnly ? but i don't know how to deal with it?
Call for login from localhost:1841 (extjs client):
Ext.Ajax.request({
url: 'http://localhost:9000/api/users/authenticate/',
method: 'POST',
params: params,
success: function(response){
var text = response.responseText;
var data = Ext.decode(text, true);
if(data.access_token){
me.saveToken(data.access_token);
me.createInterface();
} else {
if(data.message){
Ext.Msg.alert("Bummer", data.message);
} else {
Ext.Msg.alert("Bummer", "Something went wrong.");
}
}
},
Config for cors:
cors = require('cors');
...
...
...
var whitelist = ['http://127.0.0.1:9000', 'http://localhost:8080', 'http://localhost:9000', 'http://127.0.0.1:8080', 'http://localhost:1841', 'http://127.0.0.1:1841']
var corsOptionsDelegate = function (req, callback) {
var corsOptions;
if (whitelist.indexOf(req.header('Origin')) !== -1) {
corsOptions = { origin: true } // reflect (enable) the requested origin in the CORS response
}else{
corsOptions = { origin: false } // disable CORS for this request
}
callback(null, corsOptions) // callback expects two parameters: error and options
}
...
module.exports = function(app) {
....
app.use(cors(corsOptionsDelegate));
}
Other call from client:
Ext.ajax.request({
url : 'http://localhost:9000/api/users/'
method : 'POST'
success: function(response){
var text = response.responseText;
var data = Ext.decode(text, true);
...
...
}
},
})
Validation from server:
function isAuthenticated() {
return compose()
// Validate jwt
.use(function (req, res, next) {
....
....
console.log(req.headers.authorization);
validateJwt(req, res, function (err) {
if (err) {
console.log(err.inner.name);
if (err.inner.name === "TokenExpiredError") {
// client have to request token with his refresh_token
return next({"error":err.inner.name});
}
}
next();
});
})
.use(function (req, res, next) {
....
});
});
Edit 1:
I have added Set-Cookie in node and Set-Cookie appears in response headers AND in preview cookies from DevTools. But cookies is not set in browser.
exports.authenticate = function(req, res, next){
User.findOne({
fullName: req.body.username
}, function(err, user) {
....
if (!user) {
res.status(401).json({
success: false,
message: 'Authentication failed. User not found.'
});
} else {
// Check if password matches
if(user.authenticate(req.body.password)){
var access_token = jwt.sign(user, config.secrets.session, {
expiresIn: 60 // in seconds
});
res.cookie('access_token',access_token);
res.status(200).json({
"success": true,
"access_token" : access_token
//token: 'JWT ' + token
});
}else{
....
}
}
});
}
As per you using ExtJS Ajax so you can use defaultXhrHeader property to sending token from client side to sever side.
Firstly as you are calling authenticate request for getting token. Here you can use ExtJS Cookies for set and get token or cookies.
Ext.Ajax.request({
url: 'http://localhost:9000/api/users/authenticate/',
params: params,
method: 'POST',
success: function(response, opts) {
var data = Ext.decode(response.responseText;);
if (data.access_token) {
//Set cookie in our client side using Utility class for setting/reading values from browser cookies.
Ext.util.Cookies.set('access_token', data.access_token);
} else {
if (data.message) {
Ext.Msg.alert("Bummer", data.message);
} else {
Ext.Msg.alert("Bummer", "Something went wrong.");
}
}
},
failure: function(response, opts) {
console.log('server-side failure with status code ' + response.status);
}
});
Now you need to pass same token Ajax request using defaultXhrHeader
Here is example:-
Ext.Ajax.request({
url: 'http://localhost:9000/api/users/',
method: 'POST', //As per method acceptance you can use (GET,PUT,DELETE).
//send cookie sever side using defaultXhrHeader
defaultHeaders: {
'access_token': Ext.util.Cookies.get('access_token'),
'Content-Type': 'application/json;charset=utf-8'
},
success: function(response, opts) {
var data = Ext.decode(response.responseText;);
//Put your logic here.
},
failure: function(response, opts) {
console.log('server-side failure with status code ' + response.status);
}
});
As you using NodeJs in server side so you can get token from header.
Client-side JavaScript can only set cookies for the current origin.
Other origins will have their own set of cookies.
You will need to either:
Set the cookie from the :9000 origin using HTTP or
Pass the data through some other mechanism (such as a value in a POST body).

Cannot make a basic HTTP auth with node request module

I am testing my app with mocha and I would like to test a HTTP response header code depending on the credentials that I sent to it with a basic HTTP authentication.
In the client side, I made the AJAX call to the server like this:
$.ajax({
type: 'GET',
url: url,
beforeSend: function(xhr){
xhr.setRequestHeader("Authorization", "Basic " +btoa("username:password") );
},
success:function(rsp){
// do whatever I need;
}
});
And it works perfectly. It the credentials are wrong, then the website will respond wit a 302
In my test file (mocha), I try to sent the same request but for some reason it does not work.
Here is the different way I tried:
it('should return 302 because wrong credentials', function(done){
var auth = "Basic " +new Buffer("username:password").toString('base64');
var options = {
url: url,
headers: {
"Authorization": auth
}
};
request.get(options, function(err, res, body){
console.log(res.statusCode);
assert.equal(302, res.statusCode);
done();
});
});
-----------------------
it('should return 302 because wrong credentials', function(done){
request.get(url,
{
'auth': {
'username':'username',
'password':'password'
}
},
function(err, res, body) {
assert.equal(302, res.statusCode);
done();
});
});
But, in anyway, I get a HTTP 200 response code.
So why? And how should I handle it?
Ps: For those who are very cautious, the client is not to be used publicly and thus I allow myself to put credentials in it.
EDIT: To be more precise, you will find below the server code (NodeJS) which handle the request
function checkAuth(req, result, next){
var header = req.headers['authorization'];
// Ignore the preflight OPTION call
if(header != undefined){
var tmp = header.split(/\s+/).pop();
var credentials = new Buffer(tmp, 'base64').toString();
var parts = credentials.split(/:/);
var username = parts[0];
var password = parts[1];
bcrypt.compare(username, config.get.username, function(err, res){
if(res){
bcrypt.compare(password, config.get.password, function(err, res){
if(res){
next();
} else {
return result.redirect('/');
}
});
} else {
return result.redirect('/');
}
});
} else {
return result.redirect('/');
}
}
app.get('/server', checkAuth, getData.getMessages);
And the method getData.getMessage() return the following:
return result.status(200).json(res);
request automatically follows redirects so you'll need to disable followRedirect to read 3xx responses.
var options = {
url: url,
followRedirect: false,
headers: {
"Authorization": auth
}
};
For HTTP Basic authentication you can also use http-auth module.
// Authentication module.
var auth = require('http-auth');
var basic = auth.basic({
realm: "Simon Area.",
file: __dirname + "/../data/users.htpasswd" // gevorg:gpass, Sarah:testpass ...
});
// Creating new HTTP server.
http.createServer(basic, function(req, res) {
res.end("Welcome to private area - " + req.user + "!");
}).listen(1337);

Categories

Resources