Redirect If Authenticated NodeJS - node.js

I am using the following tech
NodeJS
ExpressJS
VueJS
ngnix
i store the x-access-token in the localstorage.
When the user visits the site www.example.com a vuejs component does the following
Verifies if the user is logged in by calling an authentication endpoint
If verified, it redirects to www.example.com/controlpanel
Ofcourse the problem is it takes a while for the vuejs component to load and therefore the page loads and later is redirected.
Is there a way of handling the above scenario in a cleaner way. Using ngnix even?
Thanks

In the component which is rendered on the visit to homepage(root route /)
add a beforeRouteEnter() navigation guard as follows:
//in root route component options
beforeRouteEnter(to, from, next){
myAjax.get('/auth').then((res) => {
if(res.data.user){
//user logged in
next('/controlpanel');
}else{
next('/');
}
});
}
this guard is called before the route component is rendered and only gets confirmed and rendered if you invoke next()
keep in mind you will not have access to the compnents's vue instance as the component is not created yet
to get acceess to t vue instance inside beforeRouteEnter() do this:
beforeRouteEnter(to, from, next){
next(vm => {
//acess the component's instance using vm
}
}
For more info check out In-Component Guards

Related

firebase onAuthStateChanged infinite loop node js

I'm using firebase to sign in my users on my node js app. I would like to see if the user is authentificated or not and after it redirect to the page I want (login if it not logged or dashboard).
But when I redirect user (if it not logged previously or session expires) it's looping on the same page (send redirect of the login page everytime when I'm on login page).
My function that I use actually :
function authenficated (req, res, next) {
firebase.auth().onAuthStateChanged(function (user) {
if (user) {
console.log("connected" + " " + user.uid);
next()
} else {
console.log("disconnected")
res.redirect('/') //loop on / page
next()
}
});
}
I would like a function that provides if my user is logged or not, if it logged my node backend return to /dashboard or other pages that I want and if not it cannot access to dashboard and it return automatically to / or /login
I specify I don't use React or Vue, I use simply EJS to display my pages
Thanks for all
This function/sdk is meant for frontend applications and not backend apps. You need to the admin sdk for that. You can use cookies and the admin sdk provides a function to create cookies. After a signin you attach the cookie to the headers and it will be send by the browser on every request. If the cookie header is empty than you know the user isn't signed in. To logout a user you can add a head method to clear the cookie.
To use backend function you need to use the admin sdk. This function is a front end function (web sdk ).
You can use onAuthStateChanged on the front end and redirect them from the front end. Remember onAuthStateChanged will fire on every page load.
OR implement cookies like the previous comments.
OR
Send the id token from the client via http request (fetch or axios) and verify server side using the admin sdk. Here is the specific link. This solution would require you to load something on the front end though and then send a http request to the backend, verify, then send protected resources after.
Cookies on the other hand are sent to the backend with every request, so if no cookie is present on the page load request then obviously there is no user. Or if the below function fails then server wont send protected resources. (this is explained in the link above for cookies)
getAuth().verifySessionCookie(sessionCookie, true /** checkRevoked */)

how to use passport SAML with both node (express) as backend and vue as client

I have an app with node (express) backend, and vue client.
I'm trying to add SAML SSO using passport. (makes sense to do it on the server node app).
it works perfect when used in express app. but when I applied it to a structure of express backend and vue client - it fails to make the redirection to the Idp.
when user enters my login page, vue client (Login.vue) calls node backend for verifying the user. (api verifyuser)
node call passport.authenticate('saml', ...) and I expected a response I can send back to the vue function that called me, and there, in Login.vue - to make the redirection.
but here comes the problem:
in the backend node app, the redirect response is sent after my code is executed, inside passport strategy. So it is sent automatically to the browser, not returning to the vue script that called this node api.
So the redirection is done in the background, the user don't see any redirect. the original login page is still shown.
And my vue function gets the response back from the API - only after the browser sends the redirect (in the background) to the IDP, and gets the login html page response from the IDP.
So the data I get back - is an html of the IDP login page, instead of a redirection data.
How can I solve it?
I'm new to client technologies and js and node including, so I really don't know how such a flow should be handled. searching 3 days for solution.
Thanks a lot for you assistance!
here is my snippets of code:
Login.vue:
<input class="button wide cropBottom io-mango ae-5 margin-top-0 toRight" v-on:click="userLogin" type="button" value="Log In"/>
...
userLogin: function() {
...
...
$(".overlay").show();
this.$http.post(process.env.BASE_URL + "verifyuser", oUser) //call backend node express app
.then(function(data) {
...
here I gets only an html login page which the IDP sent as a response to the redirect with the SAML Request.
}
Backend node express app:
verifyuser.js:
module.exports = function (app) {
app.post('/verifyuser', (req, res, next) => {
var SamlStrategy = passportSaml.Strategy;
passport.use(new SamlStrategy(
{ ...
});
passport.authenticate('saml', {session: false}, function (err, user, info) {
...
})(req,res,next);
//tried to get the redirect here, but res still don't have it. only after this function is called, the SAML request is created from the req, and the location url is made.
});
I've found a solution.
I changed the Vue client:
instead of calling the server using ajax, and expecting a data response to come back,
I called the server using post of a form.
that way, the browser redirects to the server when I call it, and when the passport library in the server returns a redirect response- it is done in the forground, and the user can see it.
In Single logout, passport have done a better job:
the passport API just returns the logout request created.
then I can decide myself if I want redirect from the server, or I want to send the redirection request to the waiting client function - and do the redirection from there.

Node.js / Express.js + Angular router - server overwriting client view with response object when using direct link

I am building a node.js app with express, I am hosting an Angular SPA in the public folder.
The app runs and the hosting works fine when I use the angular router for navigation around the website, but when I directly try to access the link, for example: http://192.168.1.4:3000/posts, the entire body of the website is just the JSON response object, without the app
this is the Node.js code handling the get request
postRouter.route('/')
.options(cors.corsWithOptions, (req, res) => {
res.sendStatus(200);
})
.get(cors.cors, (req, res, next) => {
posts.find({})
.then((post) => {
res.status(200);
res.setHeader('Content-Type', 'application/json')
res.send(post);
}, (err) => next(err))
.catch((err) => next(err));
})
this is my angular service sending out the get request
getPosts(): Observable<Post[]> {
return this.http.get(baseURL + 'posts')
.catch(error => { return this.processHttpService.handleError(error); });
}
Post Component .ts file
ngOnInit() {
this.postService.getPosts()
.subscribe(posts => { this.posts = posts, console.log(this.posts); },
errmess => this.errMess = <any>errmess);
}
Again, when i use my Angular 5 client app hosted in the public folder, built with ng build --prod, the JSON object is retrieved from the mongodb database and is displayed correctly on my website, along with the rest of the app, the header, the body, and the footer.
it might also be worth noting that the console.log on the ngOnInit() is not displayed on the browser when using the direct link.
Any advice/fix is greatly appreciated
You have a clash of routes between angular and your express application. Angular is served up on one route (I'm guessing the / route) and then it sort of "hijacks" the users navigation. It does this by not actually changing web pages, instead it just changes the URL in the navigation bar, but never actually makes a web request to get to that resource.
You've then got endpoints on a web server listening on those endpoints. This means the moment you visit the /posts page, you're not asking angular to do anything. In fact, angular isn't even loaded because that only gets loaded on the / route. Instead you're going straight to your API.
There are ways around this, to start with many people put their API fairly separately, either on a subdomain or mounted on /api (such as /api/posts). Then your angular app can be served up on the / route. There are other techniques you can use to then allow a user to go to /posts and still get your angular app loaded.
You can use a few approaches for this such as the hash location strategy, or you can serve up your angular application from any route on the application (* in express) and load the angular app which will then take over. This second approach is most comment, it usually results in hosting your api on a sub domain and then serving your angular app on the * route of the normal domain name. For example: api.myapp.com will serve only JSON responses, but any route on myapp.com will serve the angular app, such as myapp.com/posts.

How to make Express return a new html with axios post

I have an express server. I have two routes as get methods.
app.get('/main',(req, res) => {
res.sendFile(`main.html`, {root: staticPath});
});
app.get('/signin', (req, res) => {
res.sendFile('signin.html', {root: staticPath});
});
I want to build my app as a single page react application. But before I let the user see this single page, I want to show a sign in, sign up screen. So when user clicks the sign in or sign up buttons, I want to send signin.html as response from the express server.
Here is my code on the browser from a react class
SignIn(){
axios.get('signin');
}
I can console.log() from the express route and verify that the code gets executed within the 'signin' route, but the html view doesn't change on the browser even though I send back a html file. How do I make it happen?
I'm by no means an expert, but here are my two cents. Instead of setting up your front end to receive an HTML file from the server, a more efficient approach would be the following.
Build the signup and login pages on the front end.
Set up routing between these pages.
Send the login/signup details from client to server via /login or /signup routes that you set up in Express. These details would usually be in the req.body object (make sure to install the bodyparser package from NPM).
You could then use JWTs to authenticate users and maintain sessions.
If you're looking for server-side rendering with React, here is an article for your reading pleasure :) Sorry if I made no sense.

Show public logic if user is not authenticated React JS and Node API

How can I show only public(i.e: home, about, authentication stuff) if the user is not signed in?
I know SPA's are not meant to refresh, but I want it to change most of the scripts on the page.
Environment: Using ReactJS, WebPack with an existing NodeJS API, both on separate projects.
I went through Webpack documentation and understood that it will load only the required scripts and components, but all scripts can be seen with "View Page Source". If I understood it the wrong way, please correct me.
Ideally you track if the user is logged-in or not by storing a sessiontoken somewhere in your application state tree. You can use something like Redux to manage state in your application. You first need to decide which route you need to redirect to if the user is not logged-in & requests a route which requires authentication. Lets assume you have 2 routes /login and /products. You want to ensure that only authenticated users can view the /products section. The way you accomplish this is by redirecting to /login by checking the sessiontoken value of your state which you can pass as props to your Products component mapped to the /products route.
Use something like react-router
In the Products component use something like below
class Products extends Component{
componentWillUpdate(nextProps, nextState, nextContext) {
let {sessiontoken}=nextProps;
if (!sessiontoken)
nextContext.router.push('/login');
}
}
Products.contextTypes = {
router: React.PropTypes.object.isRequired
}
In the code above we are reading the value of sessiontoken which is passed as props from a higher order Container component. In case there is no sessiontoken it will redirect to /login. As long as your APIs return an HTTP 401 on encountering an invalid sessiontoken this will work perfectly for you and you don't need to worry about people being able to view page source.

Resources