Server Side Routing vs. Front End Routing with Proxy - javascript

I hope my question doesn't come off as silly. I have quite a bit of experience on the front end but very little on the back end.
I have a React application which uses Node.js and Express on the back-end. I have declared "proxy": "http://localhost:3001" in my package.json which I am not 100% what this does but I know it is helping to connect my server (which runs on port 3001).
The issue I am having came about while setting up Auth0 on my backend to verify users. The first thing I noticed was that I was not able to run a get request to http://localhost:3001/login instead I had to navigate the user to the url http://localhost:3001/login. I'm not sure why this is but I assume it has something to do with Auth0 settings.
After I login Auth0 returns users to a callback url. Auth0's docs recommend using localhost:3000/callback since there docs also have a backend endpoint at /callback. However after logging in the user just gets routed to an empty page at http://localhost:3000/callback and the backend endpoint is never hit. I found that strange since I was basically copying and pasting from the Auth0 guide to setting up a login with Express.
Anyway I found that if I changed the callback url to my server at http://localhost:3001/callback than the server side code runs. This makes sense other than the Auth0 docs saying to use port 3000. It seems like maybe my proxy should be linking these somehow.
The callback endpoint function looks like this:
router.get('/callback', function (req, res, next) {
console.log('called')
passport.authenticate('auth0', function (err, user, info) {
if (err) {
return next(err);
}
if (!user) {
return res.redirect('/login');
}
req.logIn(user, function (err) {
if (err) {
return next(err);
}
const returnTo = req.session.returnTo;
delete req.session.returnTo;
res.redirect(returnTo || '/user');
});
})(req, res, next);
});
When this runs successfully it should route the user to my Users page at localhost:3000/users however because I changed the callback route to 'localhost:3001/callbackthe callback endpoint is routing me tolocalhost:3001/users`.
I can kind of see what is going on. When I go to a url using 3001 I am hitting my endpoints. When I go to a url using 3000 I am viewing my front end pages. I just don't understand why the Auth0 docs would tell me to use my front end port for the callback?

I'll try to help but I'm not sure this is the answer.
If you set in your package.json the proxy to "proxy": "http://localhost:3001" then in your app to make a request you don't need to use the full URL,
axios.get('/login').then(res=>res.data).catch(err=>console.log(err));
For example without the proxy setted
axios.get('http://localhost:3001/login').then(res=>res.data).catch(err=>console.log(err));
In Auth0 the host URL and port is not a problem, U can use whatever U want, the point is the /callback route, in Auth0 you can configure a custom route for the callback but by default in your app, you need to have a route /callback. remember to add localhost:3001 to Auth0 configurations
I hope to help.

Related

Express get request with an :id-parameter being run twice

I have an API made with node and express, and the end goal is to store the :id-parameter from the request in a variable so that I can query a specific table from my SQLite database with a specific id. Now the get request with an :id-parameter is being run twice, once with the request url being what it´s supposed to be (in my case "page") and once with the url /serviceWorker.js.
This is the code from my router with the get-request:
import express from "express";
const router = express.Router();
router.get("/:id", function (req, res) {
const id = req.params.id;
console.log("id:", id);
console.log("Req url:", req.url);
res.send(id);
});
export default router
The console log from a single get request looks like this:
id: molekylverkstan
Req url: /molekylverkstan
id: serviceWorker.js
Req url: /serviceWorker.js
Even when running the get request for my home page, with this code:
router.get("/", function (req, res) {
res.render("../pages/start.ejs");
});
I get the console log:
id: serviceWorker.js
Req url: /serviceWorker.js
I tried breaking the request with break(), return, and next() but nothing worked. I have no service worker in my project which makes me wonder why it comes out of nowhere. Maybe I need som kind of service worker, or to specifically state somewhere in my project that it shouldn´t look for one?
Even though you don't have a service worker in your project, there might still be one registered in your browser from a previous project that you ran on the same domain/IP address in the past.
The reason you are getting this request is that your browser no longer has the valid cached version of the service worker and tries to reload it. But since that request fails, it will try over and over again.
To remove it, open the website in question and check your browser developer tools (Application -> Service Workers or chrome and firefox), and unregister any service workers you no longer want to use.

VueJS Secure with Auth0 - How is it secure?

I'm missing some sort of (most likely simple) fundamental understanding of securing a JavaScript application such as one using the VueJS framework and a service like Auth0 (or any other OAuth server/service).
1) If you create a SPA VueJS app with routes that require authentication, what stops a user from viewing your bundled code and seeing the views/templates behind that route without needing to login?
2) If you create a VueJS app that authenticates a user and sets some variable in a component like isLoggedIn = true or isAdminUser = true, what stops the user from manipulating the DOM and forcing these values to true?
All your JavaScript code is exposed to the client, so how is any of your code/content actually secure if it can be explored on the code level?
1) You understand correctly, nothing stops him. That's why you always do all that on the server side. The code in browser/VueJS is only to make the interface make sense, like hiding a button, but the server code should always do the actual check.
For example:
You have a button "Get secret document" that has a axios request behind to the path /api/sendsecret
In your VueJS app you can do something like v-if="user.isAdmin" to only show the button to the user.
There's nothing from stopping a user to find that path and just hit it manually with curl or postmaster or any other similar tool
Thats why the server code (nodeJS with express for example) should always do the checking:
app.get('api/sendsecret', (req, res) => {
if (req.user.isAdmin) {
res.send('the big secret')
} else {
res.sendStatus(401) // Unauthorized
}
})
2) Again, nothing. You should never authenticate a user in the VueJS application. Its ok to have some variables like isLoggedIn or isAdminUser to make the interface make sense but the server code should always to the actual authentication or authorization.
Another example. Lets say you're gonna save a blog post
axios.post('/api/save', {
title: 'My Blog Post'
userId: 'bergur'
}
The server should never, never read that userId and use that blindly. It should use the actual user on the request.
app.post('api/save', (req, res) => {
if (req.user.userId === 'bergur') {
database.saveBlogpost(req.body)
} else {
res.sendStatus(401)
}
})
Regarding your final marks:
All your JavaScript code is exposed to the client, so how is any of
your code/content actually secure if it can be explored on the code
level?
You are correct, its not secure. The client should have variables that help the UI make sense, but the server should never trust it and always check the actually user on the request. The client code should also never contain a password or a token (for example saving JSONWebToken in local storage).
Its always the server's job to check if the request is valid. You can see an example on the Auth0 website for NodeJS with Express.
https://auth0.com/docs/quickstart/backend/nodejs/01-authorization
// server.js
// This route doesn't need authentication
app.get('/api/public', function(req, res) {
res.json({
message: 'Hello from a public endpoint! You don\'t need to be authenticated to see this.'
});
});
// This route need authentication
app.get('/api/private', checkJwt, function(req, res) {
res.json({
message: 'Hello from a private endpoint! You need to be authenticated to see this.'
});
});
Notice the checkJwt on the private route. This is an express middleware that checks if the user access token on the request is valid.

How does Express and React Routes work on initial GET request from browser?

I'm new to the react world and to the fullstack world as a whole but I've searched endlessly for an answer to the following and some guidance would be really appreciated.
I'm creating an app using React and Express. It requires authentication so I was planning on using Passport to help. The client side JS uses React Routers to navigate through the website. That's all fine but my issue is with the initial GET request made by the browser.
I'll first describe my specific app requirements and then generalize what I don't understand.
As I said, my application requires OAuth2 authentication. If you try to GET a path on my website and you're not logged in, it should just load the login page. If you are logged in, then load as normal and find your path. Similar to facebook, I'd like the login URL to be the same as the "feed" page. So similar to how facebook.com '/' route is either the login page or your new feed depending on whether you are signed in, I want the same thing.
From what I understand, Passport authenticates on the back end by checking the request header. So I understand that I should have some kind of middleware that says "if user is signed in, continue down the routes otherwise render sign in page" ... How is this done? What would the code look like? My only experience with Express was from an intro class which used res.render to send back an HTML file and pass it through some template engine like handlebars. But I have no idea how it'd work with react routes. Would i still use res.render()? Something else?
Let's say my index.html has the root div to inject the react into. If I had to guess, I'd send back that index.html page with the .js file with the routes and somehow on the backend send back the route I want it to match on my react routes (either the login one or the user requested)??
More generally, I guess I'm just confused how the initial request to a website using react routes is done. 1) How does the server interact with everything to render what I asked for? 2) What would the code look like for that. My only experience with React is from a basic Udemy course that just used "react-scripts start" to render the page.
After spending the entire day Googling this question it led me to SSR which is a rabbit-hole of its own and I'm not even sure if its what I need to help me. Is it?
I'm clearly missing some fundamental knowledge as this is really tripping me up so if you have any resources to learn more just post them. Thanks!
I understand your struggle as I've had to go through it myself when combining front-end with back-end, specifically React and Node. So first things first, we know that the browser/client will always initiate a request to the server, so how does React Router take control of the routes? Well its plain simple actually, all you have to do is return the entire react app from any route from your express server. The code will look something like this:
const express = require('express');
const app = express();
app.get('/*', (req, res, next) => {
// Return React App index.html
});
app.listen(3000);
Once the react app renders on the user browser (don't worry about paths, as react will automatically render according to the URL based on the code you wrote in the client side, it will also take care of authentication vs feed page when it will scan for your local storage, cookies, etc), it will take control of routing, instead of a request going to the express server. But what happens when we request data from our server, well it returns react app on each route so we need to setup an api route to handle any data requests.
app.get('/api/v1/*', (req, res, next) {
// Return some data in json format
});
Hopefully, this gives you insight about what you were looking for.
I think the fundamental gap you're struggling with stems from that lot of those 'intro courses' shove the entire browser client into the application server to get things up and running quickly, as in, the Node server renders the entire React app AND operates as an API...
// Ajax request from React app to: http://example.com/api
app.use('/api/*'),()=> {
res.send({ <!-- some JSON object -->})
})
// User visits in browser: http://example.com/**/*
app.use('/*',()=>{
res.render(<!-- entire React App sent to browser -->)
})
The first request (assuming the user doesn't visit /api/* ) will just send down the React bundle. Further user navigation within the client would generally send XHR requests (or open WebSockets) from the React app to Express routes running on the same node program.
In many situations it makes sense to have these parts of your program separated, as by having react delivered from a completely different location than where it requests data. There's many reasons for this, but optimizing computing resources to their differing demands of CPU, memory, network .etc and manageability of code/deployment are the big reasons for me.
For example...
User visits: http://example.com *
Nginx, Apache, a 'cloud proxy' .etc direct the traffic to a static React bundle, which has no authentication and never makes contact with your Node server.
If the user has Authenticate previously they will have token in local storage (if you're using JWTs for Authentication) and your React app will be configured to always check for these tokens when you first it is initially loaded.
If the user has a token it will send an Ajax request in the background with the token as a Header Bearer and will send back user data, then redirect them to an 'Authenticated page' like the FB feed you mention.
If they don't have a token or the token Authentication fails then React will redirect them to the Login or Registration page
React
React basically high jacks the browser's native 'location' functionality (whats displayed after you domain name). So any events after the initial page load (buttons clicks and such) are handled entirely by React internally and uses those routes to determine what to display or what data to fetch from the API through Ajax (XHR).
If the user performs a hard page reload then that request will go back to the server and it will perform the whole cycle over again
React Router
Allows you to do 2 things simultaneously...
Manipulate the browser Location and History objects.
Use that History and Location information elsewhere by detecting changes and sending off events.
SSR
I've only toyed around with SSR so I can speak to it, but its provides extremely low latency for initial renders, doing it in 1 network request, so you want to use it areas of your program where thats important.
Not sure if this answers you question, but let me know if you would like me to elaborate on anything or provide some more detailed resources.
SSR is a little bit confuses for developer that has less experience, let forget it for now.
It will be more easier for you to assume that frontend JavaScript (React) and backend Javascript (NodeJS) are two separate apps, and they communicate to each other via API.
here the code that show Login component and Feed component depending on whether you are signed in
import React, { Component } from "react";
import axios from "axios";
class Home extends Component {
constructor() {
const accessToken = localStorage.getItem("accessToken");
this.state = {
accessToken,
feeds: []
};
}
componentDidMount() {
if (this.state.accessToken) {
axios(`api/feeds?accessToken=${this.state.accessToken}`).then(({ data }) => {
this.setState({
feeds: data
});
});
}
}
render() {
if (this.state.accessToken) {
return <FeedsComponent feeds={this.state.feeds} />;
}
return <LoginComponent />;
}
}
and this is your backend
const express = require("express");
const app = express();
app.get('/api/feeds', (req, res, ) => {
const feeds = [
{},
{}
]
res.status(200).json(feeds);
});
app.listen(3001);
just keep in mind that they are two separate apps, the can be in two different folder, different server, different port.
Simply point Express to the folder containing your React files or build files.
app.use(express.static(__dirname + '/dist'));
where 'dist' contains the build files
See docs for more details

NextJS routing: why do there need to be different client and server routes?

I'm somewhat new to React, but wholly new to NextJS, which I'm trying to teach myself. I've been going through the NextJS 'getting started' tutorial, as well as looking at some other tutorials. I don't understand why there is a need to distinguish between client routes and routes on the server, that is, why the client route given as an example uses a query, whereas the server route does not. I know that I am not seeing the forest for the trees, so if anyone can point me in the right direction of 'grokking' NextJS routes, I'd appreciate it.
From this tutorial, on the client side we might have
<Link href={`/blog?slug=${slug}`} as={`/blog/${slug}`} prefetch>
...
</Link>
which requires us (it would seem) to set up an Express server and handle the route
/blog/:slug
OK. But why? Why isn't the local link simply
<Link href={`/blog/${slug}`} prefetch>
...
</Link>
? Or, alternatively, why doesn't NextJS handle server-side the route /blog?slug=${slug} ?
I can follow what the NextJS site 'getting started' tutorial (I input the code myself and test it) is doing, but as far as routing I am a bit lost as to what I'm doing and why. Clearly I am missing a crucial (and elementary) element here, and would appreciate clues as to the error of my ways.
If you look at the route
/blog/${slug}
Here slug can take different values as it a parameter. If you want NextJs to handle such routes you need to implement a route for each value that slug can take. For example.
/blog/slug1
/blog/slug2
/blog/slug3
And this number can grow very quickly. Hence we use an Express server so that we can intercept request to route /blog and pass slug as parameter to the blog page.
You do not need different client and server routes. That is not compulsory unless you are using client-side routing explained here, with dynamic routes.
If you do not want to use that you can switch for server-side routing with our old friend<a> which does not require separate links.
NextJS handles server-side route queries. Below is a simple example for that -
server.get("/dashboard", (req, res) => {
const actualPage = '/dashboard';
const queryParams = {
username: req.query.username
};
app.render(req, res, actualPage, queryParams);
});
In above example, when you open page - /dashboard?username=amit, you can get the value passed in URL query in your page which you can retrieve using - getInitialProps function.
To get data from URL query with server-side routing, you must create your page with getInitialProps function. Example is as below --
Dashboard.getInitialProps = async(ctx) => {
const query = ctx.query;
const username = query.username;
return {"username": username};
}
Above code sends data from url query as page props. Server returns that data to the page in req.
Now you must create _app page with getInitialProps function to make this work.

Running a node.js file from website

I have recently started using the Twilio platform to send SMS to my users. I am perfectly able to run the node.js file from the node terminal with the command:
node twilio.js
Now, my goal is to be able to send those SMS, but from my website. For instance, when the user provides his phone number and presses the "Send sms" button. How can I achieve this? I have been looking this up for a while and I came across Express platform, ajax post requests, http server, etc. But, I can't figure out how to use them. I currently make many ajax requests (POST and GET) on my site, but I'm not able to make a request to a node file.
Thanks in advance,
Here is the twilio.js file:
// Twilio Credentials
var accountSid = 'ACCOUNT SID';
var authToken = 'ACCOUNT TOKEN';
//require the Twilio module and create a REST client
var client = require('twilio')(accountSid, authToken);
client.messages.create({
to: 'TO',
from: 'FROM',
body: 'Message sent from Twilio!',
}, function (err, message) {
console.log(message.sid);
});
Being able to run any arbitrary script on your server from a webpage would be a huge security risk - don't do that. I'm not sure where you're hosting your site, or what technology stack you're running your site on, but since you mentioned Express and Node -- if you're using Express I'd recommend that you setup a route that handles an ajax request. When someone presses 'Send SMS' you send an ajax request to that route, and in the handler that gets invoked you place the Twilio logic.
Here is a very simple way to setup an Express request that calls you node module:
twilio.js:
// Twilio Credentials
var accountSid = 'ACCOUNT SID';
var authToken = 'ACCOUNT TOKEN';
//require the Twilio module and create a REST client
var client = require('twilio')(accountSid, authToken);
function sendSms(callback) {
client.messages.create({
to: 'TO',
from: 'FROM',
body: 'Message sent from Twilio!',
}, callback);
}
// Export this function as a node module so that you can require it elsewhere
module.exports = sendSms;
Here is a good start for Express.
server.js:
var express = require('express');
var app = express();
// Requiring that function that you exported
var twilio = require('/path/to/twilio.js');
// Creating a controller for the get request: localhost:8081/send/sms
app.get('/send/sms', function (req, res) {
twilio(function(err, message) {
if (err) res.send(err);
res.send('Message sent: ' + message);
});
});
// Creating an HTTP server that listens on port 8081 (localhost:8081)
var server = app.listen(8081, function () {
var host = server.address().address;
var port = server.address().port;
console.log("Example app listening at http://%s:%s", host, port);
});
Then you can run node server.js, go to your browser and go to the url: localhost:8081/send/sms and your message will be sent :)
I'd make it so the client sends a HTTP POST request to the server, and then the server will send the message on behalf of the client.
Easiest way is to use express. I'm a bit unsure of how you're serving your website from a Node.js app without using express. Do you have a custom solution or only a non-connected from end, or something like heroku or something? In any case, you can create a route that processes posts with the following:
app.post("send_twilio_message_route", function(req,res){
// this receives the post request -- process here
});
^ Note that doesn't actually create the express app. See my link below and they give examples of some of the nitty gritty and syntax.
So the above would be on the server, in your Node.js app. From the front-end client code that runs in the browser, you need to create a post. The easiest way and most likely way to do it is through $.post in Jquery. if you are using Angular there's a slightly different syntax but it's the same idea. You call post, point it to a url, and put in the body data.
Make the body of the post request contain data such the message, phone numbers,
authentication token maybe.
See this to be able to get the body from a post request and some more implementation details of how to set it up:
How to retrieve POST query parameters?
Depending on the nature of what you're doing you might consider having the sms processing stuff run separate from the actual web service. I would create the sms unique stuff as its own module and have a function retrieve the router so that you can mount is onto the app and move it about later. This might be overkill if you're doing something small, but I'm basically encouraging you to at the start put thought into isolating your services of your website, else you will create a mess. That being said, if it's just a small thing and just for you it might not matter. Depends on your needs.
Important: I highly encourage you to think about the malicious user aka me. If you don't add any authentication in the post body (or you could include it in the url but I wouldn't do that although it's equivalent), a malicious client could totally be a jerk and expend all of your twilio resources. So once you get it basic up in running, before deploying it to anything that people will see it, I recommend you add authentication and rate limiting.

Categories

Resources