Saving the Token in the Local Storage in MEAN Stack
In our previous section, we successfully added the token timer in our app. After one hour, the token will expire, our account will be logged out, and we have to log in again. The remaining part is to save the token in the local storage because if we reload the page without logout, we have to do login again. In order to store that token into the local storage, we will use the following steps:
1) We will go back to our auth.service.ts file and create a new private method, i.e., saveAuthData. We make it private because we only call it from inside this service.
2) In this method, we expect to get data we want to save, i.e., token and expirationDate. This expirationDate should be a date and not the time in seconds because the time in seconds is a relative measure and not helpful to us when we come back in the future. There, we need to have a clear idea of when the token expires.
3) Now, all that data will be serialized and stored in local storage. Accessing local storage is very easy. We can access a local storage API, and then we just call setItem() to store the value there. The value will be set in the form of a key-value pair.
We also want to set the expirationDate too.
We convert the date to an ISOString, a serialized and standard style version of the date, which we can then use to recreate it once we read in the data later.
4) We also need to add another method, clearAuthData. In this method, we will call the removeItem() method to remove the token and expiration-this clearAuthData() method is called in the logout() method to clear the local storage.
5) Now, we need to call the saveAuthData, and this method will be called in the login() method. In order to call this method, we have to create a date by creating a new constant and then we pass the information to the function.
6) Now, we will use that information to initialize our auth status whenever the app starts, and for that, we will add another method, i.e., authAuthUser(), where we try to automatically authenticate the user if we got the information for it in our local storage. For that, we also need another method getAuthData() method. In this method, we will get the token and expirationDate from local storage by calling the getItem() method like this:
8) The getAuthData() method, will be called in authAuthUser(). We will call this method and store the data into a new constant, i.e., authInformation. If we don't get the auth information, we will return nothing. Now, we will check whether the token is still valid or not and for that, we got the expirationDate. We cannot validate if it is a valid token only the server can do, but at least we can tell if it is still valid from an expiration perspective. So, we will check if the expiration date is still in the future. We will get the current date-time by creating a new date object, and we can then simply check if it is a future by creating a new constant, i.e., isInFuture, where we create a Boolean by comparing the expirationDate to the current date and time. If the expirationdate is greater than the current date and time, we have a date in the future.
9) Now, we will check isInFuture is true or false. If it is true, it means the user is authenticated, and we set this.token equals to token we have in local storage. We also set isAuthenticated to true and push that information, so we will set authStatusListener, call next and pass true to everyone because the user is now authenticated.
10) Now, we also need to set the timer. So, since that needs to be done in two places, we will probably refactor the tokenTimer code in the login() method and put it into a new place. So, we will pull it out from the subscribe method and create a new method, i.e., setAuthTimer(). In this method, we get the duration and paste the tokenTimer code here.
11) The expiresInDuration is now the duration. Now, in the subscribe method of the login() method, we will call this setAuthTimer() method and pass the expiresInDuration in the method.
12) We also need to call the setAuthTimer() method in the autoAuthUser()
This line of code will get an error because we don't have the expiresInDuration yet. So, instead of checking whether the date is in the future, we could retrieve the difference. We will replace the name isInFuture with expiresInDuration. This expiresInDuration then should be the expirationDate-now. This will throw an error, so we will attach the getTime() method with the expirationDate and the current date now.
13) Now, we know we are detecting the current timestamp from the timestamp maybe in the future. This will also be a navigate number if the current time is greater than the exipresIn. So, we will check if expiresInDuration is greater than zero because if it is, we know that the date is in the future. If it is smaller or equal to zero, it is right now or in the past, so the expiration time would be in the past, which means it is expired.
14) We get the exipresInDuration in milliseconds, but our authTimer works with seconds. We will do that by dividing it by 1000.
15) Now, everything is good, the thing which is remaining is to run that method and a great place to run this is in the app component. There, we know that this component gets loaded first when our application is starting up. So, we will implement OnInit, and in the OnInit() method, we want to use something from our auth service. So, we need to inject our auth service here too.
16) Now, in the ngOnInit() method, we will call the autoAuthUser() method from the service to kick off that automatic authentication workflow.
Now, we save all the files and go back to our angular app. We do log in, and after login, we reload the page.
17) It works fine, but the problem is our header somehow doesn't reflect this updated information. After reloading, we still see the login and sign-up button. So, the header is not getting the information about the user being authenticated. So, in order to solve this, we will go back to our header.component.ts file, and besides setting up this listener, we should also set userIsAuthenticated to this.authService.getIsAuth() for the same reason we had to do it earlier in the post list component.
Now, we will save the file, and our app will reload. We will get the header having a logout and a new post button.
Now, everything is working fine, and there is one thing missing, and that is, we are not connecting our users to our posts. We will do it later in the new section.
Download Complete Project(Authentication.zip)