Guardedly Optimistic

Authentication in a single page application can be tricky.  In the “good ol days”, your server could store a cookie in your browser, then check the validity of that cookie on each request back to the server.  Because every single page required a request to and a response from the server, you knew that this check would happen.

But with the great power of new Javascript frameworks comes the great responsibility of making sure your application is secure in different ways.  A single page app might show multiple screens without contacting the server- it’s kind of the point.  So, how do we make sure a user isn’t accessing anything unauthorized?

The basics are covered by a standard called JWT- Json Web Tokens.  These can be passed around with every request (like a cookie, but less delicious sounding) and decoded on the server to check authorization.  Basic info (email, name, etc) can also be embedded in the token (though it’s not encrypted, so nothing sensitive).  But so far, this sounds very similar to the cookie scheme.

In Angular 2, there’s a feature called Guards.  Create an AuthGuard service and you can use some simple logic to check if a user is authorized to view a view before the router takes them there.  The setup is simple (be sure to import CanActivate from @angular/router in your file and decorate as an @Injectable):

@Injectable()
export class AuthGuard implements CanActivate {
  loggedIn: boolean = false;

  canActivate(
    next: ActivatedRouteSnapshot, 
    state: RouterStateSnapshot): Observable {
        //your authentication logic goes here!
        if(my.auth.logic) this.loggedIn = true;
  }
}

To be honest, I don’t use the next or state parameter at this point (though I might in the future). The idea is to return a boolean that lets the route know if access to this route is authorized.

In your routing code, you just add the canActivate property to any route you want to protect with this guard:

canActivate: [AuthGuard]

I know you folks familiar with Typescript are yelling at me right now; “You’ve set the function to expect a return of type Observable, idiot!”.  And that’s true.  I am generally an idiot.  But in this case, it works.

An Angular guard can return a simple boolean, or a Promise or Observable that returns a boolean.  Side note: I used Observable here because that seems to be the preferred flow of Angular- you have to convert to a Promise from an HTTP request if you want that type.  I realize though that a single boolean result is probably more of a Promise than an Observable.

Why would you do this?  Well, I found that authentication in a single page app can be trickier than just guards and jwts.  For instance: a user logs in and gets their loggedIn variable set to ‘true’.  That user can now access any route protected by the AuthGuard service.  But what if the page does do a full refresh (I know- it shouldn’t, but it does happen).  That auth is wiped out and the user gets to log in again.

So, I added a bit more logic inside the canActivate method.  The basics are: check local/session storage for a jwt- if there, send it off to the server to be validated.  If valid, reset loggedIn to true and the user stays logged in, even after a refresh:

let jwt = localStorage.getItem('token') || sessionStorage.getItem('token');
if(jwt) {
    return this.backendService.getData('yourapiurlhere');
} else {
    this.loggedIn = false;
    this._router.navigate(['/login']);
    return Observable.of(false);
}

The backendService call is just a wrapper on Angular’s http service to add any necessary headers, etc- it helps make a more REST oriented structure. It puts the jwt in the header as your ‘Authorization: Bearer …’ parameter. It returns an Observable (convert to a Promise if you prefer) and when resolved, provides that boolean to allow/deny access.  If there’s no jwt, this person isn’t logged in anyway- we redirect to the homepage and make sure the loggedIn var is set to false.

One last note: because the function is set up to return an Observable, we can’t just return false from the ‘failure’ branch.  We use one of the awesome RxJs library’s manipulation functions.  ‘of’ will make an observable of a value (a simple ‘false’ in this case).  Perfect for this situation.

So- a user can log in, and stay logged in, even if the page refreshes.  As with most of my code/thoughts, I realize there’s probably a better or cleaner way, but this one seems pretty cool to me!

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s