Authentication logic for sessions that last while tab is open - javascript

Assume you are working on a front end application that performs authentication through 3rd party api. Successful authentication returns a json web token.
What would be best practices to store such token and create some sort of session for user while he is active on the website i.e. didn't close a tab or browser, however refreshing / reloading a page should not destroy such session.
Also, how can this session be used to protect routes? I am working with a stack consisting of react / redux / node / express and quiet a few other libraries. I believe I can perform certain checks within my react-router, however wouldn't it be better to do these on the express side?

You can store the token in localStorage or sessionStorage, and include it in every API request.
Local storage outlives the tab, it's stored there until you explicitly delete from it, so refreshing a page won't be a problem. Even closing a tab and then coming back won't be.
Session storage allows you to store data. Page refreshes are fine, but tab closing isn't, which is closer to the behavior you want.
As for protecting routes, the server should obviously check the token on requests to all protected API routes.
On the browser side, you will probably want to show a login form if a user tries to visit a protected route but the token isn't there (or is invalid).
With react-router, you could do it like the official repo shows in the example, via onEnter hooks: https://github.com/reactjs/react-router/blob/master/examples/auth-flow/app.js
An alternative would be to create two top-level components, one for protected routes, one for public routes (like a landing page or the sign in/sign up forms). The protected handler will then in componentWillMount check if there's a token:
- PublicHandler
+ SignIn
+ SignUp
+ Index
- ProtectedHandler
+ Dashboard
+ MoneyWithdrawal

it may looks like that , with sessionStorage (JWT token is accesseble, untill browser or tab closed)
///action creator redux
export const signupUser = creds => dispatch =>{
dispatch(requestSignup());
return API.auth.signup(creds)
.then(res => {
sessionStorage.setItem('token', res.token);// <------------------
dispatch(receiveSignup(res));
return res;
})
.catch(err => {
dispatch(SignupError(err));
);
});
};
On client : handling auth through HOC redux-auth-wrapper
On server on server you can use passport-jwt strategy
passport.use('jwt',new JwtStrategy(opts, function(jwt_payload, done) {
User.findOne({where:{ id: jwt_payload.user.id }}).then(user=>{
if (user) {
done(null, jwt_payload.user);
} else {
done(null, false);
// or you could create a new account
}
},err=>{
console.log('Error ',err);
return done(err,false);
});
}));
then just add route handler
var checkJWT = passport.authenticate('jwt')
router.get('/protected',checkJWT, (req, res) =>{
res.json(req.user);
});
You don't need sessions on server for that

Related

Validating JWT Token in vue.js Router

I am using the following code to generate a JWT token:
jwt.sign(id, TOKEN_SECRET, { expiresIn: '24h' });
Once generated, I send the token to the client, which stores it within a cookie:
document.cookie = `session=${token}` + ';' + expires + ';path=/'
Furthermore, I am using vue.js Router for my navigation. From my understanding, if one adds the following code in the router file, one can insert middle-ware in order to protect some routes.
router.beforeEach((to, from, next) => {
if (to.meta.requiresAuth) {
let token = Vue.cookie.get('session')
if (token == null) {
next({
path: '/',
params: { nextUrl: to.fullPath }
})
}
} else {
next()
}
})
However, I am having difficulty understanding how can one verify the validity of the JWT token using this approach, which needs to be done on the server, where the TOKEN_SECRET is stored, and not on the client side.
Let me start with this: your goal in guarding routes is to prevent the user from having a bad experience by proceeding to a page that will attempt to retrieve information that they are not authorized to view.
So, you don't need to validate the token on the client side. Since a token will only be in hand if the server validated the user and returned a token, you - the author of the client code - can use the presence of the token as a means to inform what route to take the user through.
In other words, the client having a token is all the validation you need to allow the user through to protected routes.
Remember, it is not as though a protected page has private data in and of itself. A protected page will always retrieve that protected data from the server, which means that the server has the chance to authenticate the token after all.

Correct way to implement Github OAuth in client-side application?

I'm adding OAuth into my github clientside application. I have the final auth token being returned successfully, but I feel like I hacked my workflow.
Current Architecture Flow:
1) User clicks href link from component to hit the initial OAUTH route
2) Retrieve token from Github for user identity
3) Github redirects to my server route and my server route sends an additional POST to the /access_token request page with the client_secret, id and code from the above step.
4) Finally I redirect from the above route back to my UI and set a URL parameter in the process
5) In the componentDidMount I strip the final auth token from the window.url and set it in my state
Note: I plan on storing the token in Redux later, but this is the base
level as to what I'm doing.
Actual Code
Server
app.get("/login", async (req, res) => {
// Get the identity token from GitHub origin
return await axios
.post("https://github.com/login/oauth/access_token", {
code: req.query.code,
client_id: process.env.CLIENT_ID,
client_secret: process.env.CLIENT_SECRET
})
.then(async resp => {
// Little hack to parse out the query params into an object
let data = await url.parse("http://parse.com?" + resp.data, {
parseQueryString: true
}).query;
res.redirect(
url.format({
pathname: Environment.getUrl(),
query: {
token: data.access_token
}
})
);
});
});
UI Authentication Component
export default class GithubAuthentication extends React.Component {
state = {
authToken: "DATA"
};
componentDidMount() {
let currUrl = window.location.href;
this.setState({ authToken: currUrl.split("token=")[1] });
}
render() {
return (
<React.Fragment>
<a href="https://github.com/login/oauth/authorize?client_id=b5cd37110eb31620aad7">
{this.state.authToken ? "Logout" : "Login With Github"}
</a>
<span>{this.state.authToken}</span>
</React.Fragment>
);
}
}
Questions
1) The one thing I wasn't able to figure out was to make the href link a controlled component and actually hit the auth URL with something like SuperAgent or Axios. Instead, I'm forced to use this href link, not sure why.
2) Is this actually a sensible flow for getting the final auth token?
Regarding question 2, from a security standpoint, it is better to keep access token on server-side and never send the token to client-side.
I couldn't find good written resources, so I'd like to share this video which sums up how to deal with access token clearly.
https://www.youtube.com/watch?v=CHzERullHe8&list=PL78z2Z3ZApYcKb-GDQt6ikdN2EDqmKJrT&index=12&t=419s
Take away from the video
We still don't have a good way to securely store the token on the browser
By storing the access token on the server-side and using session cookie, you can minimize the risk of access token being compromised.
To actually implement this flow, you can use cookie-session to generate session. You can also use github-passport to simplify the implementation.
https://github.com/expressjs/cookie-session
https://github.com/jaredhanson/passport-github
1) I think you should reorganize your app so that you can use a component instead of an href link. You would know whether you're authenticated or not based on the value on the state property. This value can be passed as prop to your component which is where you would put the logic of authenticated ? "Logout" : "Login" or anything else.
2) the flow is OK but you have to make sure you do server side validation of the token since it's easy to just flip the switch on the UI and the pretend you're authenticated very easily.

Explicit renewal of session tokens in Firebase JS SDK

I have implemented the signin method using Firebase Auth for several providers like that:
firebase.auth().setPersistence(firebase.auth.Auth.Persistence.LOCAL).then(() => {
let provider = new firebase.auth.GoogleAuthProvider(); // + facebook, gitHub
provider.addScope('profile');
provider.addScope('email');
firebase.auth().signInWithPopup(provider).then(result => {
// app logic here
However this code gives me 60 min lasting sessions and I want to learn how to automatically renew the current user session without being forced to login every hour.
I'm also 'listening' to the current user session state using this code.
firebase.auth().onAuthStateChanged(user => if (!user) //goto LoginPage
But it doesn't 'listen' per se, it works only when I try to navigate or update the page. So I don't know how to restrict access by the exact amount of time (e.g. 15 minutes max) using Firebase methods.
The documentation says there is a getIdToken method but I can't wrap my head around where to use this code. Should it be invoked every 60 minutes just before the expiration or it should be set at the time of login? Please give some hints or any tutorials covering this very situation.
EDIT:
Also I get this code in the console after some period of inactivity (I think less than 1 hour):
auth.esm.js:121 POST https://securetoken.googleapis.com/v1/token?key=AIza... 403
Firebase tokens are set to expire after 60 min. Then it gets refreshed for you automatically. There is no way to configure the expiration time, and you don't need to do anything special in your front-end code for that.
The only trick is that, you need to grant your application API key the permission to use the Token Service API to be able to mint a new id token for you once it's expired. This is done in the GCP console, API & Services (Credentials).
So, the code should be simple as the following
Add the user authentication state change Listener
fbAuth.onAuthStateChanged(user => {
if (user) {
// User is logged in
// Proceed with your logged in user logic
} else {
// USer is not logged in
// Redirect to the login page
}
})
Implement the login logic
fbAuth.setPersistence(firebase.auth.Auth.Persistence.LOCAL)
.then(() => {
return fbAuth.signInWithEmailAndPassword(email, password)
.then(userCredential => {
// Login success path
})
.catch(error => {
// Login error path
});
})
.catch(error => {
// Persistence setting error path
})
You can set the Authentication State Persistence before the login, depending on your use cases auth-state-persistence.
Make sure that your application API key has access to the Token Service API in the GCP console
This is under
GCP Console | APIs & Services | Credentials
Then edit the corresponding key to your deployment environment to grant the API key the access to the Token Service API.
Good luck ;)
Hello first I am gonna say sorry fro my bad english. I dont really understand firebase but i think it should work if you write something like this:
firebase.auth().setPersistence(firebase.auth.Auth.Persistence.SESSION).then(() => {
let provider = new firebase.auth.GoogleAuthProvider(); // + facebook, gitHub
provider.addScope('profile');
provider.addScope('email');
firebase.auth().signInWithPopup(provider).then(result => {
// app logic here
I meant that you should have firebase.auth.Auth.Persistence.SESSION insted of LOCAL

Passport.js - Send back data to react/redux app, while redirecting after login

I'm creating a React/Redux app and am new to setting up the backend with Node/Express and authentication with Passport. What I'd like to have happen is the user logs in, credentials are checked, and if user is found from database, redirect the user to the next page and return user's info so I can update reducer.
My endpoint to login works as I think it does, as I'm able to access req.user object and am getting back the correct user info upon successful authentication. Where I'm stuck is redirecting the user to another page, while also passing along that user's info so I may update redux store.
EDIT: So I updated response by sending user info after authentication as well as the next route to redirect the user. Since I'm using redux, I perform login action, and upon getting a response, I redirect user with window.location. This partially solves my problem as even though I redirect after logging in, I believe that after updating window.location, my redux store gets refreshed, and I lose any information I grabbed server side.
app.post('/api/login', passport.authenticate('local-login', { failureRedirect: '/login'}), (req, res) => {
res.json({
redirect: '/profile
userInfo: req.user.dataValues})
})
})
export const login = (email, password) => {
return(dispatch) => {
axios
.post('/api/login', {
email: email,
password: password
})
.then(resp => {
dispatch({
type: 'LOGIN_USER',
data: resp.data
})
window.location = resp.data.redirect
})
.catch(errors => {
console.log(erros)
})
}
}
You're losing your state because you are forcing a page reload with window.location = resp.data.redirect. You should use a router with your application to do the url changes (such as react-router-dom). You can programmatically change the urls by using pushState (or maybe hashRouting?) instead of redirecting the way you currently are.

How to go about creating temporary authentication for a website?

I'm new to authentication with websites, and I've been doing a lot of reading on the different kinds of user authentication (for example session vs token authentication) you can use. However, a lot of it seems more than what I need, and I'm not sure which ones will be suitable for my cause.
My idea is to generate temporary user accounts and passwords that will expire after the first use. I want this integrated with my website, so they have one chance to view restricted pages, after which they will not allowed access to those parts again (unless provided with new credentials).
Any direction in the right step will be appreciated.
Update: I'm using Javascript(Node) as my server side language
Session-based authentication is actually incredibly lightweight if you're using a Node backend, due to most (if not all) webserver libraries supporting "middleware", which modify requests before they hit your route functions. The Express-compatable middleware client-sessions is fantastic for this, and I used it previously in a project with great success. It adds a cookie on the first request a user makes to your site which identifies them, and if at some point they log in, you can flag that session as authenticated, store session information, and other data related to them specifically.
Assuming you want both login & logout, the simplest way would to be to use POSTs over HTTPS to login & logout routes. Inside of the resolution for the login route, you would simply "mark for deletion" inside whatever database you're working with.
An example might look like this:
var app = express();
function authenticate(user, pw){
//do your application specific login verification here
}
function deleteAccount(user){
//do your application specific user removal here
}
app.use(require("express-session")({
secret : "YOUR-SECRET-KEY-HERE"
cookieName : "Session"
//any other desired config options go here
})
app.post("/login", function(req, res){
var user = req.body.user;
var pw = req.body.pw;
req.Session.isAuthenticated = authenticate(user, pw)
if(req.Session.isAuthenticated){
markForDeletion(user, pw);
}
res.write("logged in as: " + user);
res.end();
});
app.post("/logout", function(req, res){
deleteAccount(req.Session.username);
req.Session.username = "";
req.Session.isAuthenticated = false;
res.write("logged out!");
res.end();
});

Categories

Resources