Best way to enforce user/authentication state in Ember.JS app - authentication

Working on my first EmberJS app. The entire app requires that a user be logged in. I'm trying to wrap my head around the best way to enforce that a user is logged in now (when the page is initially loaded) and in the future (when user is logged out and there is no refresh).
I have the user authentication hooks handled - right now I have an ember-data model and associated store that connects that handles authorizing a user and creating a user "session" (using sessionStorage).
What I don't know how to do is enforce that a user is authenticated when transitioning across routes, including the initial transition in the root route. Where do I put this logic? If I have an authentication statemanager, how do I hook that in to the routes? Should I have an auth route that is outside of the root routes?
Note: let me know if this question is poorly worded or I need to explain anything better, I will be glad to do so.
Edit:
I ended up doing something that I consider a little more ember-esque, albeit possibly a messy implementation. I have an auth statemanager that stores the current user's authentication key, as well as the current state.
Whenever something needs authentication, it simply asks the authmanager for it and passes a callback function to run with the authentication key. If the user isn't logged in, it pulls up a login form, holding off the callback function until the user logs in.
Here's some select portions of the code I'm using. Needs cleaning up, and I left out some stuff. http://gist.github.com/3741751

If you need to perform a check before initial state transition, there is a special function on the Ember.Application class called deferReadiness(). The comment from the source code:
By default, the router will begin trying to translate the current URL into
application state once the browser emits the DOMContentReady event. If you
need to defer routing, you can call the application's deferReadiness() method.
Once routing can begin, call the advanceReadiness() method.
Note that at the time of writing this function is available only in ember-latest

In terms of rechecking authentication between route transitions, you can add hooks to the enter and exit methods of Ember.Route:
var redirectToLogin = function(router){
// Do your login check here.
if (!App.loggedIn) {
Ember.run.next(this, function(){
if (router.currentState.name != "login") {
router.transitionTo('root.login');
}
})
}
};
// Define the routes.
App.Router = Ember.Router.extend({
root: Ember.Route.extend({
enter: redirectToLogin,
login: Ember.Route.Extend({
route: 'login',
exit: redirectToLogin,
connectOutlets: function(router){
router.get('applicationController').connectOutlet('login');
}
}),
....
})
});
The problem with such a solution is that Ember will actually transition to the new Route (and thus load all data, etc) before then transitioning back to your login route. So that potentially exposes bits of your app you don't want them seeing any longer. However, the reality is that all of that data is still loaded in memory and accessible via the JavaScript console, so I think this is a decent solution.
Also remember that since Ember.Route.extend returns a new object, you can create your own wrapper and then reuse it throughout your app:
App.AuthenticatedRoute = Ember.Route.extend({
enter: redirectToLogin
});
App.Router = Ember.Router.extend({
root: Ember.Route.extend({
index: App.AuthenticatedRoute.extend({
...
})
})
});
If you use the above solution then you can cherry pick exactly which routes you authenticate. You can also drop the "check if they're transitioning to the login screen" check in redirectToLogin.

I put together a super simple package to manage session and auth called Ember.Session https://github.com/andrewreedy/ember-session

Please also take a look at :
http://www.embercasts.com/
There are two screencasts there about authentication.
Thanks.

Related

What exactly does the Express.js next() function do and where does is live in the express package?

I am learning node.js and express.js in pursuit of becoming a full-stack javascript developer. Currently, I am learning express.js and the idea of middleware.
As I understand it, middleware is basically functions that have access to modify the request and response within the req-res cycle. Is this correct?
However, I am a bit gray in the idea of the next() function. I understand that it is designed to call the next middleware function in the flow of middleware functions, however, where does it come from. Where can I find it in the express.js package.
When you have, more middlewares, they will run in order, and each middleware will pass the result to next middleware. imagine you have a route that can be accessed only by authenticated users.
router.get("/products", adminController.getProducts);
this says, whenever a user makes a request to /products, run the controller for this route. However, if you want to show this route, only to authenticated users, you will write a custom middleware, check that a user is autenticated, is user authenticated you will let the adminController.getProducts otherwise you will show an error message. So you will be placing the middleware between.
router.get("/products", isAuth, adminController.getProducts);
Note that you could pass more than one middleware. (adminController.getProducts is also a middleware but I mean besides isAuth you could place as many as you want)
isAuth will be something like this:
export const isAuth = (req, res, next) => {
if (!req.session.isLoggedIn) {
return res.redirect("/login");
}
next();
};
Imagine you setup a session based project. When user logs in, express-session (you will get familiar) will add session.isLoggedIn=true to the req obj. So before user attemps to react "/products", you will be checking if req.session.isLoggedIn is true. If yes you will let the next middleware to run, if not you will be redirecting the user to "/login" route.

Incorporating sendEmailVerification method in frontend handler or backend signup method?

I'm trying to incorporate an email verification step in the signing up process of my app. Looking at the docs online, seems like doing it in the front-end seems like the way to go.
Problem is the examples I see online have the entire sign in process done in the front-end, and just simply include the the sendEmailVerification method.
sendEmailVerification Method
firebase.auth().currentUser.sendEmailVerification().then(function() {
// Email sent.
}).catch(function(error) {
// An error happened.
});
I (instead) built my sign up method in the backend and its respective handler in the front.
Front-End Sign Up Handler
authHandler = () => {
const authData = {
email: this.state.controls.email.value,
password: this.state.controls.password.value
};
this.props.onTryAuth(authData, this.state.authMode);
// ontTryAuth is a backend action that creates new users in Firebase
};
Is it a good idea to include the sendEmailVerification method into this front-end handler code? If so, how do I go about doing it?
Yes you can use it. First this method is built by Firebase because people who use Firebase don't always/never have a server. You can yes build your own signup method in your server, but why you would use Firebase if you start to override all the stuff they give you? For me I see Firebase as a prototyping tool and so I use all the features they give, so that let me put an app working faster.
Let me know if that make sense.

Auth0: Validating id_token/JWT on UI (javascript) level

Update March 2019
I just went over this question again; the Auth0's github code has been updated in December 2018. They are now storing 'access_token','id_token' and 'expire_at' into the object/session, instead of localstorage and using now an 'isLoggedIn' flag to mark if authenticated or not. Check the pull request and these 2 lines in the specific commit: line1 and line2.
If you do not need to re-validate 'id_token' - like I was doing in the original question - that might be an alternative. Otherwise check original question.
Original Question
We are using auth0 for one of our clients. One stack that we are using it for is:
React/Redux UI
NodeJS backend
So we are using a cross origin authentication using implicit grant for that, using JWT with an RS256 algorithm. We also refresh tokens in background using silent authentication.
I was able to validate 'access_token' on the API (nodejs) side using node-jwks-rsa for express
On the UI level, after going through the source code of the auth0-js library I noticed that the "parseHash" method used in their provided react samples, actually validates tokens before we store them in localstorage, ie on successful authentication. Mainly this line in the source code.
Then I used their sample code that allows us to check if a user is authenticated, method isAuthenticated().
Problem with the isAuthenticated() method
From a security perspective, if later on (post authentication) a user of the application decided to manually modify the 'expire_at' label in the storage, they could get away as indeed authenticated. While of course there is additional security checking in our app, I wanted to update this function to validate 'id_token'. So far, I couldn't find any example in auth0's online docs for how to do that.
After digging in their source code I found a method validateToken that is being used. So I decided to leverage it in one of our functions:
import IdTokenVerifier from 'idtoken-verifier'
.... Some code in here ....
reValidateToken() {
return new Promise((resolve, reject) => {
// Both of these are stored in localstorage on successful authentication, using the parseHash method
let id_token = localStorage.getItem('id_token');
let transactionNonce = localStorage.getItem('app_nonce');
this.webAuth.validateToken(id_token, transactionNonce, function(
validationError,
payload
) {
if (!validationError) {
resolve('no validation errors for id_token');
}
if (validationError.error !== 'invalid_token') {
reject(validationError.error);
}
// if it's an invalid_token error, decode the token
var decodedToken = new IdTokenVerifier().decode(id_token);
// if the alg is not HS256, return the raw error
if (decodedToken.header.alg !== 'HS256') {
reject(validationError);
}
});
});
}`
Now, for it to succeed; we store the nonce in localstorage after successful authentication, does this approach create back doors for potential security holes? if it does; what is best practice to validate RS256 JWT id_token(s) on a UI level?

Redux, actions, authorization

I'm currently using redux and redux-thunk middleware.
When it comes to controls regarding action dispatching, such as:
does the user have sufficient permissions for this action?
prompt the user to confirm his action (for destructive action)
I believe placing such controls inside async actions (thunk) is the way to go, because:
it keeps my code DRYer (many components/views could trigger the
action, whereas there is only one actionCreator for said action)
it's the last point before "something happens" in the app. Making it feel like a strategic place to make such controls.
The question(s)
I'm looking for feedback from other redux users. I'm fairly
confident of this decision, but having little feedback (and being
junior dev) makes me doubt. Is this the right way to go for
authorization controls when using redux?
What about making the authorization controller into
middleware. It would keep auth controls in a single place instead of duplicating it in every actionCreator.
Edit
When digging deeper into this possibility it quickly became challenging because middleware initially only receive (dispatch, getState) meaning that an authorization middleware would need to "know" which action is being dispatched (or which actionCreator is being used), something that required a hacky-ish setup and eventually proved un-reliable.
Other points
Yes, this is client-side. Yes, we also make server-side checks.
I know that these types of controls should NOT be in my store/reducers. They need to be pure.
I think you are good to go with your setup. Thunk is a good way for orchestrating your program-flow. There are also other Middlewares like redux-saga which is a bit more sophisticated but as far as i understand you want to do something like this (pseudo code)?
function authorizeAndTriggerAction(forUser) {
return function (dispatch) {
return authorizeUser().then(
action => dispatch(concreteAction(forUser)),
error => dispatch(notAuthorized(forPerson, error))
);
};
}
This can be done with thunk.

How to modify current user's attributes and persist them through the entire session

I'm authenticating my users using IMAG/Ldap-Bundle (BorisMorel/LdapBundle) and I can't persist any changes made to my User to my LDAP server. But whenever a user logs in, I need to check some stuff locally and add the user's roles according to some rules.
Whenever imag verifies the user/password on my LDAP server, it'll call a service I created that's listening to the 'bind' event. Here's how it goes:
ldap_user_verifier:
class: MyBundle\Service\LdapUserVerifierService
arguments: [ #security.context, #doctrine.orm.default_entity_manager, #twig ]
tags:
- { name: 'kernel.event_listener', event: imag_ldap.security.authentication.pre_bind, method: loadUser }
Note: bind_username_before is set to false, which means LdapUserVerifierService::loadUser will only be called after user's logged in and the User class is loaded on my security.context.
Then I have my LdapUserVerifierService::loadUser like this:
public function loadUser(LdapUserEvent $event) {
$ldapUser = $event->getUser();
[...]
$ldapUser->setLocalUser($localUser);
$ldapUser->addRole('ROLE_USER');
[...]
}
That works great, except for that whenever my user changes page (from /login_check to /dashboard, for example), my modifications to the security.context.getToken().getUser() are lost. My user has a localUser and ROLE_USER associated on /login_check, but it doesn't on /dashboard.
Because my user is not loaded from my app's database, I can't persist it on the database to be loaded on subsequent pagehits and, therefore, can't persist my object changes without saving on another session variable.
Does anyone know what I'm supposed to handle this?
Thank you.
There's just not enough code to provide a better answer, but I don't see where you modify the security.context or the token.
Once you made changes to the user object that you got from the token, you probably need to set this modified user to the token.