Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 2 - JWT auth

I'm using RC1 with the new router (not the deprecated one).

I've read most of the blogs and docs out there, but I really couldn't find an idiomatic way to do it, specially not with the "new" router. So far I have my app working "perfectly", just missing a couple things:

  1. How should I go about adding the token to the Authorization header on every single http request? (Like an interceptor in Angular 1.x.)
  2. How can I intercept any 40x response and if needed (meaning the route is protected) navigate to another url?
  3. How can I set up the routes (or components) so that the app will navigate to the login url if the user is not logged in?
  4. Bonus: is it idiomatic to load the basic user data in the main component's contstructor?

I don't need a complete demo or anything like that, just a couple bullet points where I should head.

like image 707
Andrew Avatar asked May 25 '16 21:05

Andrew


2 Answers

I had to deal with the same issues not so long ago, and came up with the following solution. I don't know if it's best practice, and really liked the interceptors of Angular 1 as a solution for this, but this works for me:

I created a wrapper service for the built-in Http service. When I want to use Http I inject this service instead.

@Injectable()
export class HttpWrapper {
    constructor(private loginService:LoginService, private http:Http, private router:Router) {
    }

    get(url: string, options?: RequestOptionsArgs): Promise<Response> {
        let promise: Promise<Response> = this.http.get(url, this.addHeaders(options)).toPromise();
        return new Promise((resolve, reject) => {
            promise.then(success => {
                resolve(success);
            }, error => {
                this.onError(error);
                reject(error);
            });
        });
    }

    //... repeat the same concept for post, put, delete...

    private addHeaders(otherOptions?: RequestOptionsArgs): RequestOptions {
        let headers = new Headers({'Content-Type': 'application/json', token: this.loginService.token});
        let options = new RequestOptions({ headers: headers });
        if (otherOptions) {
            options.merge(otherOptions);
        }
        return options;
    }

    private onError(reason) {
        if(reason.status === 401) {
            this.router.navigateByUrl(`/login?${encodeURIComponent(this.router.lastNavigationAttempt)}`);
        }
    }
}  

*Note that I'm using the deprecated router. I'm waiting for the Angular team to document the new one properly.

I think this pretty much answers your questions 1-3. As for the bonus question, it's more a matter of use cases. If you know you're going to use the user's data in any case, then preloading the user's data makes sense. Otherwise, in order not to overload the application right on the start, you can only load this data when needed.

like image 155
Yaron Schwimmer Avatar answered Oct 20 '22 13:10

Yaron Schwimmer


You can look at the Angular 2 Auth which implements basic token auth and deals with routing to login page in case of being unauthorized. It's for the deprecated router (I guess) but you get the idea.

https://github.com/teonite/angular2-auth

like image 35
Andrzej Piasecki Avatar answered Oct 20 '22 14:10

Andrzej Piasecki