JWT deauthentication in React Redux App - javascript

I am having a tiny issue wrapping my head around how I would go about deauthenticating a user in the most efficient manner in my React/Redux application. (Using Redux Thunk as well).
Getting the token from the server is a piece of cake. Currently I:
- Send POST request with email and pw
- Receive Token back from server
- Save it to local storage.
Any additional requests after that to the server requires attaching the token inside an AUTHORIZATION header, which is fine.
Lets say that I walk away from the app after being logged in for awhile, then come back and decide to try to view another protected route. Lets call this route, "/latest-videos", which sends out an AJAX request to fetch the latest videos.
When that request is sent, the server determines that my token has expired, and will not allow me access to this resource. Obviously, this is where I would want to implement some type of action creator in Redux that will go ahead and redirect the user to the login page.
Do I need to perform some type of check on every AJAX request to see if the token has expired? It seems like doing that would require unnecessary boilerplate in every file that I have an AJAX request written.
This is where things get muddy for me. If we assume the token has a predetermined expiration date, how can I go about deauthenticating a user in the most efficient manner, without filling my app with poor code design choices?
You can assume I have a folder in my app called "actions" that contains files like so:
- actions
- videos.js
- users.js
- projects.js
- ...
Within a given file inside of the actions folder, you could have multiple Thunks that perform AJAX calls. Here is boilerplate example of what one of them may look like:
export function fetchVideos(query) {
return async (dispatch) => {
try {
dispatch({ type: FETCH_VIDEOS })
let res = await axios.post(`${API_URL}/videos/search`, {
query: query
})
// dispatch some success action creator with the data
}
catch(e) {
console.error('ERROR FETCHING VIDEOS: ' + e)
dispatch({ type: FETCH_VIDEOS_FAILED })
}
}
}
Hopefully I am making some sense...any help would be appreciated.

No need to check the token in your react app. Your server should be the one checking your token’s validity/expiry upon every request.
Since we’re talking about client application consuming restful api calls, server should be the one restricting the resources upon invalid token and return the 401 unauthorized response.
Upon that response, client app should deauthenticate a user and redirect to the login page (or send a request with a refresh token if you have any to avoid unnecessary login action).

Related

Sending cookies between Flask and javascript and using Flask-session

I am a web-dev noob but I'll try my best to be clear about the problem, explain my approach, and what I've tried. I also include imports in-case those are causing the problem but I'm pretty sure I've isolated it to what I describe.
I am trying to use Flask-session to keep information private but some values are "lost". This code is trimmed down significantly for simplicity. The user lands on /send and we render the loading template. loading.js does fetch() on /deploy while it runs an animation, then() we go to /results when the deploy function is done.
loading.js
function navigate() {
window.location.href = 'results'; // redirect to results page when done!
}
// deploy the contract while the loading screen goes then navigate to results page
const data = fetch('deploy').then(navigate);
loopThroughMessages(messages);
main.py
from flask_session import Session
app = Flask(__name__,
static_folder='static',
template_folder='templates')
# for the session, i.e passing values
app.config["SESSION_PERMANENT"] = False
app.config["SESSION_TYPE"] = "filesystem"
app.config.from_object(__name__)
Session(app)
#app.route('/send')
def main():
# take url parameters and do stuff with them
return render_template('loading.html')
#app.route("/deploy")
def deploy_contract():
session['contract_address'] = some_fnc()
# fetch() requires that this function return a json
return {}
#app.route("/results")
def serve_results_page():
# pull saved values from the session
data = {'contract_key' : session['contract_address']
} # calling session here causes the error, the contract_address key doesn't exist
return render_template('results.html', data=data)
So contract_address is saved to the session but when we get to /results, the server has no way to associate that session with the client.
We want to keep our contract_address private so sending it to loading.js is not an option. I'm guessing that since http is stateless, I need to pass a cookie to and from my js and python files but I'm a bit lost on how to implement it. Are cookies unnecessary (because the server doesn't actually need to receive any data from my js files)? Should I be using redirects or something besides fetch()?
Hacky fixes, different approaches, and resources are all welcome. I feel like I'm close, like there's a simple way to use cookies that I'm overlooking.
I will be continuing to research and detail the approaches I'm considering
Edit1: Looking at Flask's should_set_cookie method
Try fetch with credentials:'include' to cause browsers to send a request with credentials included on the server side calls:
fetch('deploy', {
method: 'GET',
credentials: 'include'
}).then(navigate);
Using this, you will access session['contract_address'] in the results route.
The flask-session sets a cookie with a key session in your browser, fetch with credentials:'include' includes this cookie value in the network call.
Session in flask is implemented as a client session, saving all session content as client cookies. The flask-session extension provides some other server storage for session. E.g. app.config["SESSION_TYPE"] = "filesystem" save session content in a file on the server.
But both of the approaches still depends on Cookie. The server-side session storage need to get a session_id from client Cookie.
You need to enable cookie sending on Fetch API.
fetch, sending cookies

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

How to redirect web application flow to specific page when session ends?

I have a web application developed on AngularJS / Javascript, back-end is Java / Spring. I have an issue related to session management for my web application.
I have set the session timeout using the web.xml session-timeout parameter in session-config like below,
<session-config>
<session-timeout>1</session-timeout>
</session-config>
Now after 1 minute, the session times out. I have a scenario where I need to redirect my web application flow to login page after the session has timed out.
Scenario 1 : If I click on any link / button which needs to load a new page, it automatically detects that the session has timed out and it redirects the application to login page. THIS WORKS FINE.
Scenario 2 : BUT if the page contains any drop-downs that I select, the application doesn't redirect to login page. THIS IS THE ISSUE.
What happens generally is when I chose any value from drop-down, it makes a rest call to back-end and fetch the data needed to fill in the values on the page. Now if the session has ended after a minute, and if I select the drop-down, it doesn't make any call to back-end as the session is over.
Now, in this scenario what should be done to make sure that even when I chose the drop-down and if the session is over, it will detect it somehow and redirect the application to login page. Is there a way using angular JS or javascript to check if the session is still alive when I chose the drop-down value and can redirect the flow as per need?
Considering the fact that when I chose the drop-down the flow doesn't go to back-end, I guess I might need to handle this redirection at client side only (front-end) instead of back-end. Not sure how to do that though.
Any help would be appreciated.
You can make use of http intercetor to help you here. Basically, interceptor will be executed every time you make a request, make an error while making a request, when you response or when you get error in response. Depending upon response status, you can redirect the control to an error page.
app.factory('CustomHttpInterceptor',[ '$q' , '$location', function( $q , $location, TimeoutBroadCaster ){
return{
request: function(config) {
return config;
},
requestError: function(config) {
return config;
},
response: function(res) {
return res;
},
responseError: function(res) {
if(res.status != 200){
$location.path( 'timed-out' );
}
return res;
}
}
}
]);
And then in config method at application start up, you push this interceptor in queue with
$httpProvider.interceptors.push('CustomHttpInterceptor');
To make things easier, at server end, you can come up with some custom error status which can help you determine if session had timed out and write check specifically for that condition.

How to make sure that only a specific domain can query from your REST api?

I have an app that has a REST api. I want it so that the only requests that can be made to the REST api are ones originating from the app itself. How can I do that?
I am using a node.js+express server too.
EDIT: the app is fully a public web app.
Simply define the header in your request, what this does is, it allows requests only from a certain domain, and instantly rejects any other domain.
response.set('Access-Control-Allow-Origin', 'domain.tld');
EDIT: IF you're really keen against web scraping stuff, you could make a function to double check client's origin.
function checkOrigin (origin) {
if (origin === "your.domain.tld") {
return true;
} else {
return false;
}
}
/* Handling it in response */
if (checkOrigin(response.headers.origin)) {
// Let client get the thing from API
} else {
response.write("Send them error that they're not allowed to use the API");
response.end();
}
Above example should work for the default HTTP/HTTPS module, and should also work for Express, if I'm not mistaken.
EDIT 2: To back my claim up that it should also work for Express, I found this quotation at their documentation;
The req (request) and res (response) are the exact same objects that Node provides, so you can invoke req.pipe(), req.on('data', callback), and anything else you would do without Express involved.
I would recommend using an API key from the client. CORS filters are too easy to circumvent.
A simple approach for securing a How to implement a secure REST API with node.js
Overview from above post:
Because users can CREATE resources (aka POST/PUT actions) you need to secure your api. You can use oauth or you can build your own solution but keep in mind that all the solutions can be broken if the password it's really easy to discover. The basic idea is to authenticate users using the username, password and a token, aka the apitoken. This apitoken can be generated using node-uuid and the password can be hashed using pbkdf2
Then, you need to save the session somewhere. If you save it in memory in a plain object, if you kill the server and reboot it again the session will be destroyed. Also, this is not scalable. If you use haproxy to load balance between machines or if you simply use workers, this session state will be stored in a single process so if the same user is redirected to another process/machine it will need to authenticate again. Therefore you need to store the session in a common place. This is typically done using redis.
When the user is authenticated (username+password+apitoken) generate another token for the session, aka accesstoken. Again, with node-uuid. Send to the user the accesstoken and the userid. The userid (key) and the accesstoken (value) are stored in redis with and expire time, e.g. 1h.
Now, every time the user does any operation using the rest api it will need to send the userid and the accesstoken.

Categories

Resources