Angular 5 – Handling Token Based Authentication: Part 1

Token based authentication is popular for single page applications. A token is a security code issued by a server for authenticating and identifying users. When a user login to the system or application, the servers issues a token that expires after a specified period.

The use of token eliminates the need for the app or system to remember or store the user’s credentials. You can learn more about token based authentication here.

When creating an app that uses Token Based Authentication in Angular, you need to make the following considerations:

  1. Where will you store the token?
  2. How will you send them to the server with every request?
  3. How will you handle unauthorized (Status 401) response?
  4. How will you handle token refreshes?

To break it down, let’s look at the 4 considerations:

Where will you store the token?

Web browsers usually offer 3 types of storage: Cookie, Session Storage and Local Storage. Each storage method has its own advantages and disadvantages.

I would recommend using a Session Cookie to store your token. Why? Local storage does not get cleared when the user closes their browser and it would be difficult to clear the data on all circumstances. Session Storage on the other hand is limited to one tab per session, hence if a user opens more tabs they would have to login on each occasion (unless that’s exactly what you want).

This leaves cookies, as a method of storage and not for maintaining sessions. A session cookie will be shared across all tabs and windows in the browser and will be deleted once the user closes the browser.

This cookie would have to be set and be readable by the app, so no Http-only flag. And since sending the cookie to the server has no effect, set the path to a non-existent path to prevent that. To set a session cookie don’t set an expiry date to the cookie and the browser will know to clear the cookies when it’s closed. To set cookies using angular, use ngx-cookie-service component.

How will you send tokens to the server with every request?

You will need to send the token to the server with every request. Failure to do so, the server will not be able to identify and authenticate you hence will reject your request. To do this, you can use the authorization header and attach the token as the value of the header. The server will then read the header and get the token to authenticate your request.

To do this, you will require to intercept all http requests and attach the header automatically. You can learn how to create a http interceptor here. Then with every request you can add the authorization header inside the http request as shown below:

const Authorization = authService.getToken(); //read the token from storahe
const authReq = req.clone({ headers: req.headers.set('authorization', Authorization) }); // Clone the request to add the authorization header.
return next.handle(authReq); // Pass on the cloned request instead of the original request.

(NB: I have just used a simple header name, you can use the method of your choice like Bearer Authentication scheme)

You have now managed to send the token with every request to the server.

How will you handle unauthorized (HTTP Status 401) response?

The other consideration is handling unauthorized responses from the server. A server returns unauthorized response (HTTP Status 401) if there is an issue with the credentials i.e. invalid or if they don’t exist. The server could also return this option if the token is expired and a refresh is required (We will discuss this in the next step).

It’s important to note that unauthorized response is different form forbidden (HTTP Status 403) which means you have the correct credentials but you are forbidden from accessing a specific resource.

Since the server was unable to authenticate the user, you could redirect them to the login page or show a login modal form. To achieve this, you need to catch all error responses from the server and check for those returning status 401. Then you could redirect them to the login page as shown below:

return next.handle(authReq)
   .catch((error, caught) => {
      if (error.status === 401) {
        //logout users, redirect to login page
        authService.removeTokens();
        //redirect to the signin page or show login modal here
        this.router.navigate(['/auth/signin]); //remember to import router class and declare it in the class
        return Observable.throw(error);
    } else {
        return Observable.throw(error);
    }
}) as any;

This will simply redirect all status codes 401 to the sign in page.

How will you handle token refreshes?

It would be a bad precedent to set the token expiration to too long or have the user login to the system every few minutes because a token expired. A good compromise is coming with a way of refreshing an expired token. For instance, you could have a refresh token that last longer than the other authorization token but can only be used once. Then you can set the authorization token to expire in a few minutes and the refresh token to expire a little bit longer like a couple of hours. This way, even when the authorization token expires you can ask for a new one from the server transparently.

What I like to do is have the server return a status code that is not defined by the HTTP standard. A good example is 419 or 490. Then the interceptor can catch all 419s and attempt to refresh the authorization token. If successful, it should resend the original request with the new authorization header. If it fails, redirect the user to the login page. The refresh method would look something like this:

  refreshToken(): Observable<string> {
    let refreshAuth = this.getRefreshToken(); //get refresh token from storage
    let url: string = BASE_URL + "auth/refresh";
    return this.http.get(url, {
      headers: new HttpHeaders().set('refreshAuthorization', refreshAuth),
      observe: 'response'
    }).map(refreshResponse => {
      let authToken: string = refreshResponse.headers.get('authorizationToken');
      let refreshToken: string = refreshResponse.headers.get('refreshToken');
      //add token to storage
      this.createToken(authToken, refreshToken); // method for adding token to cookie storage
      return authToken; //return the new authorization token
    });
  }

Now you can intercept all responses with status code 419 for expired tokens and attempt to refresh the tokens. The code below shows how to handle refreshing of tokens with a custom http code 419. It should be inside the catch block of the http interceptor.

if (error.status === 419) {
  return authService.refreshToken().flatmap(t => {
    this.inflightAuthRequest = null;
    const authReq = req.clone({ headers: req.headers.set('authorization', t) });
    return next.handle(authReq); //refresh was success, resend the original request
  });
}

This will try and refresh the token and incase it fails, it will redirect the user to the login page. Now you have a simple token based authentication system in Angular. Here is the full code for the http interceptor.

11 Replies to “Angular 5 – Handling Token Based Authentication: Part 1”

  1. Hi, thank you so much for the article and thank you to all who commented and provided extra useful thoughts

    I just wanna know if there will be a part 2?

    1. Hi, am working on a part 2 to resolve some issues that may arise from this part 1 and also address those comments.

        1. Not yet. It’s in progress and I will notify you when it’s done. Anything in particular you would like to see in the new post?

  2. I implemented it both with implicit and authorization_code. The only issue is if user wants to stay logged in over time. When it’s id_token is expired.

    1. What about creating a mechanism to refresh the expired token. That’s what i would do sustain a session for long.

  3. You mention refresh tokens here, which are only available using the OAuth2 Authorization Code and Resource Owner Password Grants. These two grants should never be used with non-confidential clients such as an Angular SPA; there you should only use the Implicit Grant. To refresh a token you should see if you can leverage e.g. Open ID Connect’s &prompt=none OAuth2 extension for getting tokens headless (which in turn leverage the session of the Authorization Server).

    In short: In my opinion, recommending using refresh tokens in an SPA is somewhat dangerous. The only use case where this may be valid is when using Angular to write mobile apps (deployed to mobile phones), where you have more control over access and refresh tokens storage. But for a web application intended for use in the browser, this is not ideal. You’d need to store both client id and secret in your SPA code, and this can easily be reverse engineered to get your API credentials out. Not what you want.

    In case I misunderstood something here, I’m sorry.

    1. I get your point but in the risk also on Mobile Application are also very high. It is also relatively easy to reverse engineer any app to get access the refresh tokens so they are not safer there. Plus a authorization and refresh token in Angular SPA is not that bad, the issue you are raising is in storage of the tokens. And since you don’t have much control on the browser, this leaves majority of any authentication method you may use vulnerable to attack via stealing token in localstorage. I may be wrong but would love to hear your suggestion on authentication of an SPA or any Web App.

      1. The implicit grant is the way to go usually. This gives you a token with a very limited life span, so losing it wouldn’t be that bad. For refreshing, the OpenID Connect Extension with the additional prompt parameter can help. This could be used e.g. from within a hidden IFRAME.

        Mobile apps are usually harder to break into. Plus, you really need access to the device. And if you break in to your own device, the only thing you can get access to is an API access on behalf of your own user. This may not be intended use, but it is not half as bad as giving out your keys in a web SPA, in my opinion. I hope It all makes sense, but this is how we work with Angular, tokens and OAuth2.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.