Adding authorization token in the Angular header for Drupal 8, forbidden content.

Photo by Taylor Franz on Unsplash
Share this

The first step to protect content is on our Drupal Site. Any change in the backend is more complicated to break than in the frontend, we can achieve that by changing the user role permissions in our admin. 

Now, after that, Drupal will ask for a proof that we are a user with a specific authentication. That is our token, we get it in our login service and keep it in our local storage. So, for making the call we have two options; the first one is in our user-list service, in our get method. 

And, like any get method, if you want to send params they have to travel in the header. Something like this: 
 

  getUserList(): Observable<UserList[]> {    
    const users = this.http.get<UserList[]>(this.mainUrl, 
     { headers:new HttpHeaders().append('Authorization',`Bearer${this.auth.getToken()}`)})
    return users
            .catch(this.handleError.handleError);     	  
  }

You see, we are calling our token from our authentication method, the response from getting the data from our local storage.


But there is another way, the HTTP interceptor. It will “intercept” all the request from Drupal and add to them our token. The solution is much cleaner and scalable than the other one, and for being honest is not so hard to implement. Let’s check it out. 

addToken(req: HttpRequest<any>, token: string): HttpRequest<any> {
        return req.clone({ setHeaders: { Authorization: 'Bearer ' + token }})
    }

    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpSentEvent | HttpHeaderResponse | HttpProgressEvent | HttpResponse<any> | HttpUserEvent<any>> {
        console.log('Did you get it?');
        return next.handle(this.addToken(req, this.authService.getToken())) 
}

With the addToken() function, I’m cloning the request and set up a new header. After that, in the interceptor, once we take the request, we can call our addToken function, using the token from our authentication service. 

You can specify this interceptor to the request that you are interested, by now, in our entire app, it is triggered even in our login application, for this particular case nothing bad happened, just take in mind that this can be improved. 

And, that is all!.  In our next post, we are going to talk about how to catch errors and intercept them. Remember that we saw something about that in our login component for sending the “invalid password” message, so for now is something similar, but we need to call the refresh token for in this way get a new token and complete the initial request. 
 

Comments

Submitted by Developper Tue, 06/05/2018 - 17:58

Hello,

I have an issue with getting the token inside the interceptor...Once i'm connected, I tested what happen with messages in the console: it seems that the interceptor try to get the token but in vain because it didn't find it created yet.
First I got all the interceptor messages and after that the creation of the token happened! I'm really confused!?

Submitted by josuevalrob Tue, 06/05/2018 - 20:44

In reply to by Developper

I need to see your code for a better recommendation... 

But there is a couple of question about your logic: 

How are you saving your token? Is it in a LocalStorage?. 

Do you know how to get access to your local storage? 

On this blog, I talk more about the same project and how to manage the local storage

Submitted by Developper Wed, 06/06/2018 - 21:24

In reply to by josuevalrob

Thanks for your reply!

This is my login function (login.service):

login (user, pass): Observable<Token> {
    const url = `${this.mainUrl}oauth/token`;
    let body= new FormData();
    body.append("grant_type", this.grant_type);
    body.append("client_id", this.client_id);
    body.append("client_secret", this.client_secret);
    body.append("username", user);
    body.append("password", pass);

    return this.http.post(url, body)
        .map((token: Token) => {
             localStorage.setItem('token', JSON.stringify(token.access_token));
            localStorage.setItem('refresh_token', JSON.stringify(token.refresh_token));
            console.log("the token is: "+token.access_token);
            return token.access_token
        })

        .catch(this.handleError.handleError);

This is the  intercept function (request.interceptor):
 

intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

        console.log("intercepted request ... ");

// Clone the request to add the new header.
        const authReq = req.clone({ headers: req.headers.set('Authorization', `Bearer ${this.auth.getToken()}`)});
 console.log("Sending request with new header now ...");
        return next.handle(authReq)
            .catch((error, caught) => {
//intercept the respons error and displace it to the console
                console.log("Error Occurred");
                console.log(error);
//return the error to the method that called it
                return Observable.throw(error);
            }) as any;
    }
}

This is a part of my Auth service:
 

public getToken(): string {
        const token = localStorage.getItem('token');
        return JSON.parse(token);
    }

    public isAuthenticated(): boolean {
        const token = this.getToken();
        return !this.jwtHelper.isTokenExpired(token);
    }

I added the interceptor provider as you said (app.module) with the other services:
 

providers: [
   {
     provide: HTTP_INTERCEPTORS,
      useClass: RequestInterceptor,
      multi: true
    }

  ]

for the configuration of the token in my app.module I added:
 

export function tokenGetter() {
  return localStorage.getItem('access_token');
}
imports: [
    JwtModule.forRoot(<JwtModuleOptions>{
      config: {
        tokenGetter: tokenGetter,
        whitelistedDomains: ['localhost:4200']
    
      }
    })

  ]

By following all the part of your tutorial :

I successefully  could connect my angular app(front) with Drupal (back) by the creation of a token and I could get the token created.


The problem now is the permission to access to all of my views, I get always 403 forbidden content . when I tested I found out that the interceptor triggers well before the creation of the token, this is why the header is always sent empty to Drupal (I tested the access of my views by adding the token to the header and it worked perfectly in postman)

Thanks in advance!

Submitted by josuevalrob Thu, 06/07/2018 - 22:24

In reply to by Developper

Your code in angular looks fine.

With postman you can try all the drupal response, I wrote a post about it. 

Check if the response from Drupal is working fine. 

Try to remove all the permissions from Drupal and check it. 

A 403 error is an access problem, check how are you accessing into Drupal with postman

Submitted by Developper Thu, 06/07/2018 - 23:49

In reply to by josuevalrob

Yes I did with postman , when I don't add the Authorization to my header to have access to my view I get :

"message": "The 'access content' permission is required." 403 Forbidden

Once I add the Authorization with "Bearer + token", my view is displayed successfully with the 200 ok statuts.

Add new comment

The content of this field is kept private and will not be shown publicly.

Restricted HTML

  • Allowed HTML tags: <a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • Lines and paragraphs break automatically.
  • Web page addresses and email addresses turn into links automatically.
CAPTCHA
This question is for testing whether or not you are a human visitor and to prevent automated spam submissions.