Reverse Proxy login with credentials from node.js - node.js

I currently have a server running Spring in a Tomcat servlet with Shiro Token system for checking if a user is logged in already. It allows cross-domain requests.
In any other domain I can on the client (generally using angular) call...
http.get('https://<my_check_login_service>', {withCredentials: true})
...and as long as I am already logged in (token doesn't expire) return the user info (name, avatar, etc.).
I have another system now that is a node server (also serving up angular for the client side) for which I would like to call the node server and have it proxy over to the above my_check_login_service to get the user, set info on the session object (using express), and then return the user to the client. But also, through the session object, allow me to trust their connection and allow them to perform further api calls depending on the security level of the user returned from the login service.
On the node.js router I can proxy doing this ...
app.get('/checklogin', function(req, res) {
req.pipe(request.get("https://<my_check_login_service>").pipe(res);
}
...but I don't know how to pass the proper credentials to the service. If I do ...
http.get('checkLogin', {withCredentials: true})
...it, of course, doesn't work because the credentials for my login_service are not sent to the local server. How can I pass the correct credentials to make this work?
Cheers.

Credentials are most likely in the HTTP headers, passing all headers (both from request and to response), with the address of original request, should make it work:
app.get('/checklogin', function(req, res) {
console.dir(req.headers)
//You can inspect the headers here and pass only required values
const options = {
url: 'https://<my_check_login_service>',
headers: Object.assign(
//Tell the login service about address of original request
{'X-Forwarded-For': req.connection.remoteAddress}
req.headers)
}
req.pipe(request.get(options))
.on('response', (response) => res.set(response.headers))
.pipe(res)
}
This example passes original address by setting X-Forwarded-For, login_service may recognize it ...or not, depending on the configuration.

Related

Create cookies on other domains via javascript

I'm working on a project where I need to create a cookie in another domain of my application, I know that doing it directly is not possible because that would be a security flaw.
Example scenario:
Frontend: epictv.cf
Streaming Backend: ipv4-epictv001.infra-imm.epictv.cf
Reason: I need a <video> tag to be pre-authenticated in the streaming domain, since you can't pass any type of header in the tag.
For that I thought of making the frontend make a request to the backend and pass in the "body" of this request (GET) the value of the cookie I want to create, but for some reason when axios makes this request the cookie is not created, in however, if i open the route manually works fine!
How could I get the frontend to place a cookie on the backend?
My attempt code:
async createCookie(req, res){
const session = req.params.session;
res.cookie("sessao", session, { maxAge: 1000000 });
res.status(200).json({
"status": "ok"
});
},
PS: I know that in the video tag I could pass the url with the authentication in the src itself, but I would rather not do it.

How to store authentication token with node and express

I have two nodejs app for client and server. Client side doesn't rely on any libraries for building interfaces. It uses pure html and express routes to the requested page.
router.get('/', function (req, res) {
res.sendFile(path.join(__dirname + '/index.html'));
});
Client sends an auth request to the server via AJAX call and receive the auth token back. I need to store it somewhere and make sure express checks if token is available or not to reroute user to login page if unauthenticated (token is not available)
I was thinking to use localStorage but it is not available/accessible under express.
$.ajax({
url: 'http://server:8080/login',
type: "POST",
data: {username, password},
dataType: "JSON",
contentType: 'application/json',
success: function (data) {
localStorage.setItem("jwtToken", data.jwtToken);
},
});
Maybe your should consider store it like a cookie and all the new requests to your server will contain the necessary information to verify the auth of the client.
So that developers don't have to deal with tokens and other aspects of an authentication system, I created an npm package. You can check if the user is logged in or not with this package as well. Here is the link:
https://www.npmjs.com/package/authenticatejs

How to make HTML auth form and JSON Web Tokens communicate together in Ionic/Angular

I'm working on an Ionic application.
On the one hand I have an auth basic form in which people fill in their username and password. On the other hand I'd like to implement authentification with JSON Web Tokens and Node JS.
The workflow would be this one : as soon as a user fills in his credentials, they will be sent with a POST request. If these credentials are correct, the user can access to the application and gets an access token as a response.
The thing is that I'm a little bit lost with all that concepts. I built a form and sent informations with a POST request. I managed to create some APIs with Node JS and that's ok. I see how to build a authentified webservice too (e.g : https://github.com/jkasun/stack-abuse-express-jwt/blob/master/auth.js).
But I concretely don't understand the links between the html form and the authorisation check part..
To be clearer, how is it possible to make the html part and the Node JS scripts communicate together ?
Before posting that question I made many researches and found many stuff on building an authentified API. But there was very few advice on how to make it communicate with the client part (I mean the form), which is what I have to do.
If anyone has any ressources (document, Github examples..) on that, I'll greatly appreciate. But I would be very happy too if someone try to make me understand these concepts. I guess I have to improve my knowledge on all that so that I could test some POCs.
Many thanks in advance !
JWT General flow:
1- Authenticate using a strategy (You done it)
2- Deliver an accessToken along with response (You done it)
3- The client MUST store this accessToken (LocalStorage is the best place, not cookies: They are vulnerable to csrf attacks)
4- On every request you are going to make to a protected area (where user is supposed to be authenticated and authorized), make sure to send you accessToken along with it, you can put it on Authorization header, a custom header, directly in body of the request... Basicaly just make sure to send it properly.
5- On the server receiving client requests, you NEED to verify that token (You verify it by checking the signature of the accessToken).
6- If he is authorized, great, if not, send back an HTTP Unauthorized Error.
Here is my implementation using an accessToken on a header + passportjs-jwt:
Client code
To store token:
localStorage.setItem('accessToken', myAccessToken);
To send it:
const myAccessToken = localStorage.getItem('accessToken');
{
headers: {'Authorization', `Bearer ${myAccessToken}`}
}
Server code
1- Configure passport
passport.use('jwt', new JwtStrategy({
jwtFromRequest: jwtPassport.ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: myAccessTokenSecret,
passReqToCallback: true
}, (req, payload, done: (err?, user?) => void): void {
User
.findOne({where: {id: req.params.id}})
.then((user: User) => {
if (!user) {
return done(new Error(`No user found with id: ${req.params.id}`), null);
}
return done(null, user);
})
.catch((e: Error) => done(e, null));
}));
Pay attention to callback: If your callback is called, it means that passport has successfuly verified the token (It is valid). In my example, i get the user details in database and this is the user that will be returned and put in req.user object passed to my controller below:
2- Finally, the controller route (protected area):
.get('/users/:id', passport.authenticate('jwt'), (req, res, next) => {
// do stuff in protected area.
}
And that's it. If you want more security, check refreshTokens implementation.
I used passport because i found it relevant in my case, but you can write your own handler, by using jsonwebtoken and just calling its "verify" function.
You can find documentation of passport jwt strategy here => http://www.passportjs.org/packages/passport-jwt/

how to make an auth requset from api backend to another api backend that i own?

I want to make a simple authentication request between two API each on separate servers, i know how to make authentication using JSON-web-tokens or sessions , from front-end to back-end calls , this is done by storing them in the browser , but how i can make authentication between separate back-end servers that i own , authentication from API to another API ?
i have tried , by using jwt-simple library , and check if decoding was valid , then i complete the process , if not then i reject it , but i don't want to do it that way , I've tried passport docs , but all i can find is they describe storing authentication in the browser , since I'm trying to use fetch request from my back-end API to another API that i own , this doesn't serve the purpose that I'm trying to reach here ?
I don't understand question
At the beginning you have to answer the question: What do you want to do? You have several options:
Authorization completely without user involvement: you know how to connect a user from server A to a user from server B and only servers authenticate it and say I'm Kowalsky (Eg: an additional method for generating JWT.)
Authorization with the password: Server A asks the user to enter login + password, and then uses this data for server B.
Server A sends back the user to be authorized on server B and forwarded data back to server A. (e.g.: OAuth2)
Edit:
Add 1. Assume that you authorize using JWT and you know how to generate it for the second server, so:
Server A knows how to generate JWT for Server B and does it.
You should use a library that allows you to perform an HTTP request, or better use a REST client, eg 1 result from google node-rest-client.
In a very similar way as in the frontend-client, you build an query and send it.
const getServerBTokenForUser = function(userData) {
return 'Generated JWT token';
}
const Client = require('node-rest-client').Client;
// direct way
let client = new Client();
var args = {
path: { "id": 120, "arg1": "hello", "arg2": "world" },
headers: {'Authorization': 'Bearer '+getServerBTokenForUser(userData) }
};
client.get("http://remote.site/rest/json/${id}/method?arg1=${arg1}&arg2=${arg2}", args,
function (data, response) {
// parsed response body as js object
console.log(data);
// raw response
console.log(response);
});
It was the fastest, though not the best method, because it creates strict dependencies.
It is better to add a method on server B, where other servers will be authorized (second authorization method, eg IP or encrypted data) and obtain JWT for specified user.

Connect NodeJS as client to third party service that uses session data

I am developing a website in Node.JS / Express, and have until now used JWTs to store authentication data.
To summarize, I have an AngularJS app which calls a REST service on Node, and for authentication the user POSTs username and data to the server and gets a JWT containing the username and expiration, which then gets sent along with every request which requires authentication.
Now, though, I need to be able to connect to a third party service (which is a REST service that runs on Delphi) which uses sessions to save authentication data instead.
Using Fiddler, I can see that the service, when used in another implementation (third party) responds with JSON authentication data. In all subsequent requests, the client sends a cookie called dsessionid, although it doesn't appear in the "response cookies" in the previous response.
My question is: how do I take that dsessionid cookie in my NodeJS app and put it in my JWT so I can send it to my actual client?
I managed to solve my problem by getting the session ID in the "Pragma" header of the response (I don't know if the header is something "default" for Delphi applications or if it was specific to this application, I had to look through Fiddler entries to find out what header had the data) and then using a custom cookie jar with the request module to put the session ID in the cookies of subsequent requests.
const request = require('request-promise-native')
return request.get({
url: 'http://example.com:20202/auth',
resolveWithFullResponse: true
})
.then(res => {
return res.headers['pragma']
})
.then(sid => {
let j = request.jar()
j.setCookie(request.cookie('sessionid=' + sid), 'http://example.com')
return request.get({
url:'http://example.com:20202/fetchData',
resolveWithFullResponse: true,
jar: j
})
Hope this helps somebody.

Resources