44

I am confused about how to create a good header for a simple Get request in Angular 5.

This is what I need to do in Angular: enter image description here

This is what I have so far:

  getUserList(): Observable<UserList[]> {
    const headers = new Headers();
    let tokenParse = JSON.parse(this.token)             
    headers.append('Authorization', `Bearer ${tokenParse}`);
    const opts = new RequestOptions({ headers: headers });  
    console.log(JSON.stringify(opts));
    const users = this.http.get<UserList[]>(this.mainUrl, opts)
    return users
            .catch(this.handleError.handleError);         
  }

This is the response in my console.log:

{"method":null,"headers":{"Authorization":["Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6ImYwODZlM2FiYTk0ZjVhMjVmNDhiNzlkYmI2YWUwOWY4YzE2MTUyMzg2N2I5MDZiY2MzNWQyNWJiYTZmYTE4YjEwZjA1MjZiNThkZjE2Y2FjIn0.eyJhdWQiOiJmMDExY2M1OC00MGNlLTQzYTktOGY3MS04NDI0OTRlM2E5OTciLCJqdGkiOiJmMDg2ZTNhYmE5NGY1YTI1ZjQ4Yjc5ZGJiNmFlMDlmOGMxNjE1MjM4NjdiOTA2YmNjMzVkMjViYmE2ZmExOGIxMGYwNTI2YjU4ZGYxNmNhYyIsImlhdCI6MTUyMzU1MTQ0NSwibmJmIjoxNTIzNTUxNDQ1LCJleHAiOjE1MjM1NTQ0NDUsInN1YiI6IjIiLCJzY29wZXMiOlsiYXV0aGVudGljYXRlZCIsImFuZ3VkcnUiXX0.E-WdQTl7nPDW0gj0rohfql-QgnAinzvDxPR-pySMrG07XFY9tA6Ex7IL23pDBmKDmQO8RcZKa0L5r6SRQq9_iqzMWzn5Zxp94J9TJrpZ2KGMoLR_FbK_tpC5G5q5vUnCe3q34sH7cPdT_2cI704OWWaYmIUKKpXWUIG0PJw_uKSJ_uOifPv59RZGQkoaQ9gPywDKe-uamm1Faug-Kk2YnFMoEJq7ou19zyxgdpX80ZTPUae67uB0PGLRuvxfGaqVsJ8k0NunAY3-pyUnBwR_3eeuOxf4TyfW2aiOJ9kuPgsfV4Z1JD7nMpNtTHMJaXEyNkBW8RlYHD1pj4dkdnsDmw"]},"body":null,"url":null,"withCredentials":null,"responseType":null}

It looks pretty. But gives me this error

GET http://druang.dd:8080/user-list?_format=json 403 (Forbidden)

There is another clue to solve this mystery. In Sublime text, If I put the mouse over opts it says something like:

ERROR in src/app/services/userlist.service.ts(33,59): error TS2345: Argument of type 'RequestOptions' is not assignable to parameter of type '{ headers?: HttpHeaders | { [header: string]: string | string[]; }; observe?: "body"; params?: Ht...'. Types of property 'headers' are incompatible. Type 'Headers' is not assignable to type 'HttpHeaders | { [header: string]: string | string[]; }'. Type 'Headers' is not assignable to type '{ [header: string]: string | string[]; }'. Index signature is missing in type 'Headers'.

Any idea?? Here is the full Git repo THanks for your help!

ValRob
  • 2,584
  • 7
  • 32
  • 40
  • I think you are importing the wrong class for Headers try to check angular documentation in version 5 the http service was deprecated for httpClient service but the httpClient is in @angular/common and the other one is in @angular/http you cannot mix classes from those ones cause it will cause errors. To me your errors looks like you are using http from "@angular/common" and Headers from "@angular/http" instead the HttpHeaders from "@angular/common" – Nicu Apr 12 '18 at 17:03
  • 1
    Hi, thanks @Nicu this are my import: `import { HttpClient, HttpHeaders } from '@angular/common/http';` according to the angular [documentation](https://angular.io/api/common/http/HttpHeaders) – ValRob Apr 12 '18 at 17:08
  • Great :D @angular/http it will be replaced with @angular/common/http removed in ng 6 I suppose. – Nicu Apr 12 '18 at 19:17

9 Answers9

56

I suggest to use HttpInterceptor for setting default HTTP headers on outgoing requests rather than adding an additional HTTP header to each call.

HTTP Client - Setting default headers @ angular.io


In your example you can do the following:

import { Http, Headers, Response } from '@angular/http';

getLoggedInUser(auth_token): Observable<any> {
  const headers = new Headers({
    'Content-Type': 'application/json',
    'Authorization': `Bearer ${auth_token}`
  })
  return this.http.get(apiUrl, { headers: headers })
}
BinaryButterfly
  • 18,137
  • 13
  • 50
  • 91
Nagy Gergő
  • 578
  • 4
  • 5
23

For get requests, I used the following code and it works

import { HttpClient, HttpHeaders } from '@angular/common/http';

getServerList(){
    var reqHeader = new HttpHeaders({ 
        'Content-Type': 'application/json',
        'Authorization': 'Bearer ' + JSON.parse(localStorage.getItem('mpManagerToken'))
     });
    return this.http.get<Server[]>(`${environment.apiUrl}/api/Servers/GetServerList`, { headers: reqHeader });
}
Achala Dissanayake
  • 810
  • 3
  • 16
  • 33
Hassan Rahman
  • 4,953
  • 1
  • 34
  • 32
8

Two things:

  1. headers.append(...) does not mutate the headers object, so your authorization header is not being sent. You need to do headers = headers.append(...)

  2. Try this.http.get<UserList[]>(this.mainUrl, { headers: headers });

GreyBeardedGeek
  • 29,460
  • 2
  • 47
  • 67
  • 1) `headers = headers.append`gives me: Cannot assign Headers because it is a constant or a read-only property – ValRob Apr 12 '18 at 17:07
  • 1
    either change the declaration from `const headers` to let headers` or do `const headers = new Headers().append('Authorization', `Bearer ${tokenParse}`); – GreyBeardedGeek Apr 12 '18 at 17:11
  • With `let` it said: `Type void is not assignable to type 'Headers'` – ValRob Apr 12 '18 at 17:16
  • And the other option, works, but when I Set `const opts = new RequestOptions({ headers: headers });` I got : `ERROR in src/app/services/userlist.service.ts(33,37): error TS2345: Argument of type '{ headers: void; }' is not assignable to parameter of type 'RequestOptionsArgs'. Types of property 'headers' are incompatible. Type 'void' is not assignable to type 'Headers'.` – ValRob Apr 12 '18 at 17:17
  • Also, if i forgot about the options, and go straight to the `{headers:headers}` in the http get request, I got this: `ERROR in src/app/services/userlist.service.ts(35,59): error TS2345: Argument of type '{ headers: void; }' is not assignable to parameter of type '{ headers?: HttpHeaders | { [header: string]: string | string[]; }; observe?: "body"; params?: Ht...'. Types of property 'headers' are incompatible. Type 'void' is not assignable to type 'HttpHeaders | { [header: string]: string | string[]; }'.` – ValRob Apr 12 '18 at 17:18
  • I found the solution... If you can explain me, thanks!. `const users = this.http.get(this.mainUrl, { headers:new HttpHeaders().set('Authorization', `Bearer ${tokenParse}`)})` – ValRob Apr 12 '18 at 17:34
8

In Angular 6 and 7, this method can be used to intercept all HTTP request and add the bearer token.

Implementation tutorial is available here. Youtube, this channel has all the tutorials.

Interceptor component

import {
  HttpInterceptor,
  HttpRequest,
  HttpHandler,
  HttpUserEvent,
  HttpEvent
} from '@angular/common/http';
import { Observable } from 'rxjs';
import { UserService } from '../shared/user.service';
import { tap } from 'rxjs/operators';
import { Injectable } from '@angular/core';
import { Router } from '@angular/router';

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
  constructor(private router: Router) {}

  intercept(
    req: HttpRequest<any>,
    next: HttpHandler
  ): Observable<HttpEvent<any>> {
    if (req.headers.get('No-Auth') === 'True') {
      return next.handle(req.clone());
    }

    if (localStorage.getItem('userToken') != null) {
      const clonedreq = req.clone({
        headers: req.headers.set(
          'Authorization',
          'Bearer ' + localStorage.getItem('userToken')
        )
      });
      return next.handle(clonedreq).pipe(
        tap(
          succ => {},
          err => {
            if (err.status === 401) {
              // this.router.navigateByUrl('/login');
            } else if ((err.status = 403)) {
              // this.router.navigateByUrl('/forbidden');
              // alert(err.localStorage.getItem('userToken'));
            }
          }
        )
      );
    } else {
      this.router.navigateByUrl('/login');
    }
  }
}

Guard component

import { Injectable } from '@angular/core';
import {
  CanActivate,
  ActivatedRouteSnapshot,
  RouterStateSnapshot,
  Router
} from '@angular/router';
import { Observable } from 'rxjs';
import { UserService } from '../shared/user.service';
import { ToastrService } from 'ngx-toastr';

@Injectable()
export class AuthGuard implements CanActivate {
  constructor(
    private router: Router,
    private userService: UserService,
    private toastr: ToastrService
  ) {}
  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): boolean {
    if (localStorage.getItem('userToken') != null) {
      const roles = next.data['roles'] as Array<string>;
      if (roles) {
        const match = this.userService.roleMatch(roles);
        if (match) {
          return true;
        } else {
          // tslint:disable-next-line: quotemark
          this.toastr.info("You don't have access to this page");
          this.router.navigate(['/login']);
          // this.router.navigate(['/forbidden']);
          return false;
        }
      } else {
        return true;
      }
    }
    this.router.navigate(['/login']);
    return false;
  }
}

Add it to app.modules.ts

providers: [
    ConfirmationDialogService,
    UserService,
    DoctorService,
    { provide: OwlDateTimeIntl, useClass: DefaultIntl },
    { provide: OWL_DATE_TIME_FORMATS, useValue: MY_MOMENT_FORMATS },
    AuthGuard,
    {
      provide: HTTP_INTERCEPTORS,
      useClass: AuthInterceptor,
      multi: true
    }
  ],

Then the guard is added to route

 {
    path: 'adminPanel',
    component: AdminPanelComponent,
    canActivate: [AuthGuard],
    data: { roles: ['Admin'] }
  },
Arun Prasad E S
  • 9,489
  • 8
  • 74
  • 87
3

I have used all the above suggested formats to append the headers with access token, its adding null like "Authorization Bearer null" in the Request header. If I print the accesstoken just before the line of adding/cloning headers, the accesstoken value is being printed in the browser console. Here's the format I am using.

console.log("Inside Interceptor accesstoken : " + this.oauthService.getAccessToken());
    req = req.clone({
      setHeaders: {
         Authorization: 'Bearer ' +  this.oauthService.getAccessToken()
      }
    });
    return next.handle(req);
bts_dev
  • 83
  • 1
  • 7
2

I am not very good at programming,but with a little of try and failure if found this:

  getUserList(): Observable<UserList[]> {
    let tokenParse = JSON.parse(this.token)    
    // let myHeaders = new Headers();
    // myHeaders.set('Authorization', `Bearer ${tokenParse}`);
    // let options = new RequestOptions({ headers: myHeaders});
    const users = this.http.get<UserList[]>(this.mainUrl, { headers:new HttpHeaders().append('Authorization', `Bearer ${tokenParse}`)})
    // const users = this.http.get<UserList[]>(this.mainUrl, options);
    return users
            .catch(this.handleError.handleError);         
  }

It doesn't really matter if I use .set or .append, at the end of the day, it works in both cases...

I don't really know what is happening, so, if someone wants to explain it in the comments, you are welcome...

ValRob
  • 2,584
  • 7
  • 32
  • 40
2
'Authorization': 'Bearer ' + access_token,

that worked

masaldana2
  • 635
  • 9
  • 20
2

While @HassanRahman shows it for get requests, for post requests,

import { HttpClient, HttpHeaders } from '@angular/common/http';

getServerList(){

    postData = { your data }
    var reqHeader = new HttpHeaders({ 
        'Content-Type': 'application/json',
        'Authorization': 'Bearer ' + JSON.parse(localStorage.getItem('mpManagerToken'))
     });
    return this.http.post<Server[]>(`${environment.apiUrl}/api/Servers/GetServerList`, postData, { headers: reqHeader });
}
Achala Dissanayake
  • 810
  • 3
  • 16
  • 33
  • 1
    In my opinion very important answer, I don't know why downvoted. In my case I had post method on server without parameters, so had `this.router.post('https://localhost:5001/api/method', null, {headers: { 'Authorization': \`Bearer ${localStorage.getItem('authToken')}\`, }}) .subscribe(data => { //now use data window.location.href = data; });` Of course it is better to use interceptor, but I think that it is also important to see simple basic example like this with both `post` and `get`. – Lazar Đorđević Oct 11 '21 at 15:52
  • @LazarĐorđević Thanks for your comment – Achala Dissanayake Oct 13 '21 at 05:11
0

ALTERNATIVE WAY Set HttpHeader using set or append function

const reqHeader = new HttpHeaders().set('Authorization', 'Bearer ' + this.accessToken);

return this.http.get<any[]>(this.webApiUrlEndPoint, { headers: reqHeader});

rajquest
  • 535
  • 1
  • 5
  • 10