A Token Walks Into a BarΒ ...

SPA

Ado Kukic

Developer Evangelist

Auth0

@kukicado

SPA (Angular)

Security Best Practices

...

https://ng-thor.com

User

https://api.ng-thor.com

https://app.ng-thor.com

ngThor

OK, ngThor

JSON Web Tokens

JWT's (RFC 7519) are an open industry standardΒ  method for representing claims securely between two parties.

JSON Web Tokens

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOmZhbHNlfQ.uI_rNanTsZ_wFa1VnICzq2txKeYPArda5QLdVeQYFGI

How is a Drivers License like a JSON Web Token?

Header

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOmZhbHNlfQ.uI_rNanTsZ_wFa1VnICzq2txKeYPArda5QLdVeQYFGI

Drivers License

New York State

{
  "alg":"HS256",
Β  "typ":"JWT"
}

Payload

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOmZhbHNlfQ.uI_rNanTsZ_wFa1VnICzq2txKeYPArda5QLdVeQYFGI

Picture

Name

Address

Demographics

Restrictions

{
Β  "sub": "1234567890",
Β  "name": "Thor Odinson",
Β  "admin": true
}

Signature

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOmZhbHNlfQ.uI_rNanTsZ_wFa1VnICzq2txKeYPArda5QLdVeQYFGI

UV Light

Hologram

HMACSHA256(
  header + "." + payload,
  "lokisucks"
)

πŸ“

/v1/orders
{ "status": 401 }
/v1/auth
{ 
Β  "status": 200,
  "jwt" :"eyJhbGciOiJIU.." 
}
/v1/orders

-H "Authorization: Bearer eyJhbGciOiJ..."

{ 
Β  "status": 200,
  "order_id" : 138,
Β  "total_cost" : 27.99,
Β  ...
}

JWT and Angular

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Injectable()
export class MyAppService {
  private url = 'https://api.ng-thor.com/v1';

  constructor(private http: HttpClient) { }

  login() {
    return this.http.get(`${this.url}/auth`);
  }

  getOrders() {
   return this.http.get(`${this.url}/orders`);
  }
}

HTTP Client Library

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders} from '@angular/common/http';

@Injectable()
export class MyAppService {
  private url = 'https://api.ng-thor.com/v1';

  constructor(private http: HttpClient) { }

  login() {
    return this.http.get(`${this.url}/auth`);
  }

  getOrders() {
   let headers = new HttpHeaders(
    { 
      Authorization: "Bearer " + localStorage.getItem("jwt")
    }
   );
 
   return this.http.get(`${this.url}/orders`, {headers: headers});
  }
}

HTTP Client Library

HTTP Interceptors


import { Injectable } from '@angular/core';
import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';

@Injectable()
export class JWTInterceptor implements HttpInterceptor {

  constructor() {}

  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    
    request = request.clone({
      setHeaders: {
        Authorization: `Bearer ${localStorage.getItem("jwt")}`
      }
    });

    return next.handle(request);
  }
}

HTTP Interceptors


import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs/Observable';
import { AuthService } from './auth.service';
import { Router } from '@angular/router';

@Injectable()
export class AuthGuard implements CanActivate {

  constructor(private authService: AuthService, private router: Router) {}

  canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {

    if (!this.authService.authenticated) {
      this.router.navigate(['/login']);
      return false;
    }

    return true;
  }
}

Route Guards

import { Routes, RouterModule, CanActivate } from '@angular/router';
import { LoginComponent } from './components/login.component';
import { CheckoutComponent } from './components/checkout.component';
import { AuthGuard } from './auth/auth.guard';

const routes: Routes = [
  {
    path: 'login',
    component: LoginComponent
  },
  {
    path: 'checkout',
    component: CheckoutComponent,
    canActivate: [
      AuthGuard
    ]
  }
];

Route Guards

Summary

JSON Web Tokens are excellent for securing Angular applications.

Angular's excellent HTTP Library makes it easy to work with JWT's.

Single Page Application security is mainly concerned with authorization.Β 

A security guard couldn't stop Thor, but your server can refuse requests without valid JWT's.

Thank You

@kukicado

Β 

http://bit.ly/ng-spa-demo

http://bit.ly/ng-auth-series

A Token Walks Into a Bar

By Ado Kukic

A Token Walks Into a Bar

  • 1,382