Adding the Token to Authenticate the Requests in MEAN Stack
Our previous section we successfully implemented and used our check-Auth middleware to protect certain routes against unauthenticated access. Now, we want to use that token on the frontend and actually store it when we do log in to then attach it to our requests we send on the backend. We will use the following steps to add the token to authenticate the requests:
1) First, we will go to our auth.service.ts file, where we do login. We will define a new property, which will be of type string. Initially, this property will be undefined, but in the login() method where we get our response, we know that this response will hold the token. So, we should be able to extract the token from the response. There should be a token property, and we can configure this post request to be aware of it like as:
2) We want to use that token in other parts of the app. We want to use it in the posts service for certain requests. For that, we will add a new method in our auth service file because the token field is private. We could turn it into a public one, but we will simply add a new method here, i.e., getToken(), and there we will return this token.
3) Now, we will go back to our service.ts file and get that token to use it. Now to use it, we need to inject the auth service into the posts service and then add a header to all our outgoing HTTP requests. We will use a different way of doing that, we will create a so-called interceptor for our HTTP client, and that is a feature offered by the angular http client. We can add an interceptor, which are functions that will run on any outgoing HTTP request, and we can then manipulate these outgoing requests, for example, to attach our token, and that is exactly what we want to do.
So, we will create a new file in our authentication folder and give it the name auth-interceptor.ts to indicate that we have an interceptor in there.
4) Now, this is an official feature provided by the angular http client, and we create such an interceptor by creating a normal class and giving it the name AuthInterceptor. This class has to implement an interface provided by angular, i.e., HttpInterceptor, and we define the intercept() method like this:
5) This intercept() method takes two arguments. The first one is the request we are intercepting because we mentioned this runs for outgoing requests, and this is of type HttpRequest, and this is a static type that could wrap all kinds of information and data.
6) The second argument is something we might know from the middleware on the NodeJS side. We have the next argument too, and this interceptor works a lot like middleware, just for outgoing instead of incoming requests. Therefore, we have no response object because we can't configure a response. We are just involved in sending the request.
But we do get that request, and we get next that allows us to leave that interceptor and allow other parts of our app, for example, the parts where we subscribe to the response. We allow these parts to take that request and its response. So, that is why we need next to allow the interceptor or the request in that interceptor to continue its journey through our app, and that next argument is of type HttpHandler.
7) This method has to return something, and this method will return a call to next.handle(). This handle method is provided by next, and here we allow the request to continue its journey. So we could just pass the request in the handle method, and this would be a valid interceptor that doesn't do anything. This will just take the request and allow it to continue without being changed.
8) Now, we will change it though, we will create a new constant which should hold our token, and for that, we need to inject our auth-service into this interceptor because we can get the token from there. The service that receives that injected service has to have the @Injectable annotation to inject services into other services. We added that to all our other services anyway because of the way we provided them. We will provide the interceptor differently because the angular http client requires us to provide it differently.
But we still need to add an empty injectable annotation so that we can actually inject services into this service, which is a requirement by angular.
9) Now, we will use the authservice in this interceptor class. We will use it to create a new token by simply calling the getToken() method of our authservice class like this:
10) Now, we manipulate the request to hold this token, and we should clone that before we manipulate it. We have to do that because if we directly edit that outgoing request, we will cause unwanted side effects and problems due to the way requests work internally and handle internally. So, we will create a new constant, and there we will call request's clone() method, which will create a copy of that request. We can pass the clone's configuration to clone not only the request but also edit the clone. We want to edit it, and actually, we want to edit its header to be precise.
The header should be our original request headers, but we also want to see an extra header, which we can do with the set.
11) The set sounds like it would override all old headers, but it doesn't. It only adds a new header, and it sets the value for it, but if that header already existed, it will override it. So, in the clone function, we will set the authorization header, and the value will be our authToken.
This will create a request which holds this authorization header with our token, and it is now the authRequest which we want to forward, which now should leave our app.
12) Now we are taking or manipulating an incoming request, and we are adding our token on the authorization header. And to be very precise, this would not work. Remember that thing about the bearer word we mentioned. Our value actually should be the bearer, then whitespace and then the authToken like this:
This is how we extract data on the backend, we could omit this, and it is just a convention we often see.
a. The first property is the provide property, and there we provide a token, i.e., HTTP_INTERCEPTOR. This token is imported from @angular/common/http.
b. Because now we are telling angular, hey for this identifier which angular will look for, the angular http client will look for that, for this token we want to provide a new value. That value is then provided with the useClass property, and here, we have to point at our interceptor, i.e., Auth-interceptor.
c. Now, we can have multiple interceptors in an app, so we set the third value, i.e., multi and set its value to true.
This simply tells angular doesn't overwrite the existing interceptor, add it as an additional one instead, and the angular http client will handle the internals.
Now, our interceptor is registered, and every outgoing request will receive that token. It also means that requests that don't need that token will receive it, but there will be undefined and should not be a problem.
We will go back to our application and try to insert a new post after logging.
Note: We will get the "Request header field Authorization is not allowed by Access-Control-Allow-Headers in preflight response". We will get this error because we don't allow this header. So, we will allow this header on the backend in the app.js file and set the Authorization header like this:
Now, if we go to our angular app, we didn't get that error.
Now, everything is working well, but our header looks bad. We will improve the UI header to reflect the authentication status in the next section.