NodeJS authentication middleware fails after successful login - node.js

I have an angular app running on localhost:8000 and a node express api with passport authentication on localhost:3000.
After the user login the server returns a successful response but when I try to call other services it fails on the authentication middleware. It doesn't make sense since the login was successful. The user should be authenticated!
Using postman I was able to call authenticated services successfully, but when I make calls from my angular application it return that the user is not authenticated, even after a successful login.
Authentication middleware:
exports.isAuthenticated = (request, response, next) => {
if (!request.isAuthenticated()) return next(createError(401, 'Você não está autorizado.'));
next();
};
When I move the api to a real domain everything works. I thinks it's something related to the localhost x localhost connection but don't know what. I need both applications running on the same domain since it's a requirement for my Facebook application.
I'm on this problem for weeks, tried different solutions but nothing works. I don't know more what to do!
The request and response settings:

Related

Node.js Express API doesn't send headers if its docker image is deployed

I've built an Node.js Express API where whenever the user uses the (POST) /login, if logged successfully, the api will set the Authorization Token such as this:
#Post('/login')
#UseBefore(validationMiddleware(LoginUserDto, 'body'))
async logIn(#Res() res: Response, #Body() userData: LoginUserDto) {
const { cookie, user } = await this.authService.login(userData);
res.setHeader('Set-Cookie', [cookie]);
return user
}
Whenever I run the docker image locally, if it was requested by a React app it would create the token as a cookie in the browser successfully.
Since it was working, I deployed in docker image of the API in Azure and Digitalocean (in order to see if would work on both. But when I tried to login with the deployed API, it would POST with success but the cookie wouldn't be set in the browser when using the React App (in the app the credentials were set to true in order to save).
I tried to call the deployed API with Postman and Insomnia and both would save the cookie from the successful login.
With this last experiment I was really confused because the API works as expected both in postman and in the react app when run locally, but when deployed only works as expected in postman and not in React. I can't understand if the problem is from react or from the API.
I have also tried using RTK and Axios in react and both got the same results.
In the CORS options from the API the origin is set to "*"
Already found out, seems like when creating the cookie I was not setting the Same-Site property and by default was Lax, which didn't let the browser save the cookie. I set it to none and needed to put secure after it.
public createCookie(tokenData: TokenData): string {
return `Authorization=${tokenData.token}; HttpOnly; Max-Age=${tokenData.expiresIn}; SameSite=None; Secure`;
}

How to authenticate angular 10 client app from node/express js using passport-google strategy?

I'm building a web app that is being used on top of microservices architecture.
Using node/express js I have implemented auth service and products service both are listening on different ports like
http://localhost:8001 for authentication service
http://localhost:8002 for products service.
Kong Gateway used to authenticate and connect the microservices with jwt. Implemented passport-jwt and passport-local strategy to authenticate the users from client side using post calls.
Finally I have implemented the google auth on server side using passport-google strategy in this below URL
http://localhost:8001/auth/google -> it directs me to google auth consent screen after sign in it is redirecting to below Url
http://localhost:8001/auth/google/callback with token. it works fine at server end.
async googlecallback(req, res, next){
passport.authenticate('google', {
session: false,
}, (err, user, message) => {
if (!user) {
return next(new UnAuthorizedException(message))
}
const token = user.generateToken()
user = UserTransformer.transform(user)
user.token = token
this.Response(res, user, message) // sending response to client using custom method
})(req, res)
}
. When I come to authenticate the user from angular app client side. I'm unable to proceed further. just struggling here. :-(
How can I authenticate the user when they click google sign in button in angular 10 on client side?
My front end app Url like http://localhost:4002/account/login
Tried to use window.open("http://localhost:8001/auth/google","_blank") method, not working as expected.
res.setHeader('x-code', 'jwthere'); header method. Also tried to pass the JWT token with URL parameter. but both seems unsecure.
http://localhost:4002/account/login?token=7wF8bit5W1Pfi5Glt1X8H0YQu8BN7OeNRcX1zbj3AGpUHaYSxLlNIjHpzuw
security is the major concern here. I want the google sign in like khanacademy social login
https://www.khanacademy.org

Express application for Authentication as seperate microservice

Current Situation:
I am currently working with a specific oauth provider and i am hosting my applications as microservices in a kubernetes cluster.
My end user is actively working with an angular application hosted as a docker container using nginx as webserver.
Now my idea was to integrate the authentication as a seperate microservice using node.js express and passport. so The workflow would be
User hits login in angular and gets redirected to the express application (same host address just a different endpoint /auth/someProvider)
The express application has no user interface it just handles all the oauth redirecting and communication with the provider, after the user information has been collected it redirects back to the angular application.
Now this works pretty for one last part. When my /auth/provider/callback would redirect inside of the express application it is very easy to access the request object that has been extended with the user object. when I redirect to an external website I get the cookie and everything but not an easy way to access the user object.
My acutal question(s):
Is there a safe way to pass that user information from the Request object directly to be used by the angular application (Best way i could think of is to use the headers as they are encrypted as well in https but still seems kind of hacky).
Is ita good idea in general to use OAuth that way.
The big advantage to this solution would be that I could use the same Docker Container with many web projects not having to implement Authentication one by one by just changing ClientId and Secret Env Vars in that Docker Container.
OK this is how I made it work.
basically you implement the basic concept described in the passport.js Documentation and add a seperate endpoint to access the userinfo. This is why I will describe where it starts to differ a bit
Step 1: Authenticate user at the Gateway
As described in the passport.js documentation. The authentication microservice needs the following callback (The router here is already served under /auth)
router.get("/provider/callback", passport.authenticate("provider", {
failureRedirect: "https://your-frontent-app.com/login",
}), (req, res) => {
res.redirect("https://your-frontend-app.com");
});
When you get back to your Web-Application you will see the Session-Cookie has successfully been stored.
Step2: Get User Info from Endpoint
Now we need the second endpoint /auth/userinfo in our routes.
router.get('/userinfo', (req, res) => {
if(!req.session) return res.status(401).send();
if(!req.session.passport) return res.status(401).send();
if(!req.session.passport.user) return res.status(401).send();
return res.json(req.session.passport.user).status(200).send();
});
Not very pretty this block with the 3 if's but it happened to me that all of those combinations could be undefined
Now, with the session cookie stored in our browser we can call that endpoint from our front-end with the credentials (I'll use axios for that)
axios.get('https://your-authenticator.com/auth/userinfo', {withCredentials: true})
.then(res => {
//do stuff with res.data
});
Now theres one more thing to note. If you want to use credentials to call that API setting the Access-Control-Allow-Origin Header to * will not work. You will have to use the specific host you'll be calling from. Also you will need to allow the Credentials in the Header. So back in your main Express app make sure you use the headers like
app.use((req, res, next) => {
res.header("Access-Control-Allow-Origin", "https://your-frontend-app.com");
res.header("Access-Control-Allow-Credentials", "true");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Auth, Authentication, Authorization, Credentials");
next();
});

Problem accessing to REST API from devices on same network

I have a REST API running in my PC and vuejs web app sending request.
When I try the app in localhost, found perfectly.
I can access to home ('/') and using the web app, it send others requests at the API ('/something')
But, i need to try app from my mobile, so I connect both at same network and access to localhost from IP.
I can access to home (IP:port) and the app responde from my mobile.
I can access to others endpoints too (IP:port/something).
Normaly only the app use API endpoints. (Useless for the user to access directly)
The problem is: I'm on home page from my mobile, but at start, the web app send a request to an endpoint. But the server respond 0 to status :(
I try with other PC and same... when i try my app from others devices, the app can't use my API.
Connexion to home: (server.js (API))
MyRouter.route('/')
.all(function(req, res){
res.render('home.ejs');
});
Request sended when user access to home (when Vue mounted): (app.js (Application))
mounted () {
this.$http.get(this.website + '/connexion' ).then(response => {
//succes (I need to get some infos from API)
}, response => {
//error
}
Endpoint: (server.js)
MyRouter.route('/connexion')
.get(function(req,res){
res.json({foo: "bar"}); //some infos
})
From localhost I can get json info but from others device I can access home page but the request to endpoint return request status = 0. When I try to access directly to the endpoint it found ! But I need to still on home page...
Some of the situations that produce this status code:
Illegal cross origin request (see CORS)
Firewall block or filtering
The request itself was cancelled in code
I'd bet it's CORS or firewall problem.
Ok, I find the problem... xD From others device i access to the web app from server IP but the variable 'this.website' used in requests was always "localhost" ! So I replaced that by current URL...

Get Google Plus user access_token in Azure webapp server

I have set up an Azure webapp successfully running Node.JS with Express and added a Google Plus authentication using the built in Azure Google "Authentication / Authorization". The auth process works just fine using SSL and and I am able to get users authenticated.
Now,
I know the auth process is calling https://mysite.azurewebsites.net/.auth/login/google/callback with the user access_token for future API calls but in this case Azure "intercepts" it (instead of what will normally happen - I would get it on my won server).
The question is - Is there any why to get and use this token on the server?
I have tried to add a route to the .auth/login/google/callback and somewho get the code
router.get('/.auth/login/google/callback', function (req, res, next) {
console.log("CALLBACK");
next();
});
to no avail...
The auth info from google+ will be set in request headers. If you list your request headers in a router function like:
res.send(JSON.stringify(req.headers));
You can the auth info are set in the headers with the prefix x-ms-token-google-.
Refer to https://azure.microsoft.com/en-us/documentation/articles/app-service-api-authentication/ for more details.
Meanwhile, you can simply issue a GET to the /.auth/me endpoint on your site for retrieving additional user information as well as any tokens required for graph calls. Refer to https://azure.microsoft.com/en-us/blog/announcing-app-service-authentication-authorization/ for details.

Resources