Thank you for reading my blog posts, I am no longer publishing new content on this platform. You can find my latest content on either mainawycliffe.dev or All Things Typescript Newsletter (✉️)
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:
To break it down, let’s look at the 4 considerations:
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.
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.
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.
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.
Angular 5 was finally released after several delays yesterday, November 1, 2017. It was also accompanied by Angular CLI 1.5. This is a major …
Read MoreIf you are a fan of Angular, there is some good news, Angular 5.0 will be released on 23th October – that’s next week. If you are wondering …
Read MoreIntroduction A HTTP Interceptor enables you to catch HTTP requests and responses so that you can modify them. It is very useful especially …
Read MoreWeb developers require from time to time to create different types of images sliders and carousel in their apps. Most developers coming from …
Read MoreAngular 5 was finally released earlier this week after several delays. It brings a lot of improvements over Angular 4 and new features as …
Read MoreLast week, I briefly touched on Yarn Package Manager in my post about 5 must have tools for angular developer. Yarn Package Manager – simply …
Read More