How to add Authorization Header to Angular http request?
Asked Answered
H

5

47

This is my first post.

I've just started learning Go and Angular and I'm attempting to connect the angular app to a go api. I've written both and am stuck identifying the root of the problem. I thought it was a CORS problem, but it works fine if I don't include the headers line of code in my Angular http request. At this point I'm just trying to add the header. The authorization code isn't implemented yet.

Both apps are running locally with the Go app on port 5000 and Angular on 4200

Angular http request that doesn't work:

this.http.get<ProjectedBalance>(requestUrl, {headers: new HttpHeaders().set('Authorization', 'my-auth-token')})
    .subscribe(data => {
     this.projBalance = data.projBalance;
   }

Angular http request that works:

this.http.get<ProjectedBalance>(requestUrl)
    .subscribe(data => {
     this.projBalance = data.projBalance;
   }

I'm getting this error:

Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:4200' is therefore not allowed access. The response had HTTP status code 403

I'm using the gorilla/mux and gorilla/handlers in my go code

router := mux.NewRouter()
router.HandleFunc("/home/{endDate}", GetProjBalance).Methods("GET", "OPTIONS")
headersOk := handlers.AllowedHeaders([]string{"X-Requested-With, Content-Type, Authorization"})
originsOk := handlers.AllowedOrigins([]string{"*"})
methodsOk := handlers.AllowedMethods([]string{"GET", "HEAD", "POST", "PUT", "OPTIONS"})
//start server on port
log.Fatal(http.ListenAndServe(":5000", handlers.CORS(originsOk, headersOk, methodsOk)(router)))

Headers from Chrome Dev Tools

Request URL:http://localhost:5000/home/2020-12-21
Request Method:OPTIONS
Status Code:403 Forbidden
Remote Address:[::1]:5000
Referrer Policy:no-referrer-when-downgrade

Response Headers
view source
Content-Length:0
Content-Type:text/plain; charset=utf-8
Date:Mon, 20 Nov 2017 21:39:43 GMT

Request Headers
view source
Accept:*/*
Accept-Encoding:gzip, deflate, br
Accept-Language:en-US,en;q=0.9,uz;q=0.8
Access-Control-Request-Headers:authorization
Access-Control-Request-Method:GET
Connection:keep-alive
Host:localhost:5000
Origin:http://localhost:4200
Heindrick answered 20/11, 2017 at 20:57 Comment(6)
Consider rephrasing your post in the form of a question...Gordongordy
I'm not sure why handlers.CORS isn't working but if you DON'T use CORS, you'll need to proxy your development requests to port 5000. In production you'll be running on port 80 so there's no conflict, but since you're using angular's dev server and running your go server locally, localhost:4200 and localhost:5000 are different origins. I'm not sure what the "angular 5 way" to do this is but webpack-dev-server has an ultra simple proxy field in the package.json and you basically want to replicate that.Haldan
Hello gobuckeyes could you please provide me with the list of headers your client sends in it's request to the API (from the network tab in dev-tools). Also does the issue remain if you set all 3 CORS to {"*"}?Eyelash
@Eyelash I posted the headers from the dev-tools. Changing all three CORS to {"*"} changed the error to a 405 - Method not allowed. Thank youHeindrick
Try turning the AllowedMethods() back to what they were. There should be 2 requests sent from your client one has the method OPTIONS and the other should be GET (for this particular) request. After you revert AllowedMethods try sending the request again, and if the error persists update the question with the data from the GET request.Eyelash
@Eyelash The headers listed above are what's returned with the AllowedMethods() set as shown in the post right above them. I think I posted both the Options Request and the Get Request. I don't think I see any others in the dev tools.Heindrick
E
88

Regarding the best way of handling Authentication headers in Angular > 4 it's best to use
Http Interceptors for adding them to each request, and afterwards using
Guards for protecting your routes.

Here's a full example of an AuthInterceptor that I'm using in my app:

auth.interceptor.ts

import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
import { Injectable } from '@angular/core';

import { Observable } from 'rxjs/Observable';

import { AuthService } from './auth.service';

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    req = req.clone({
      setHeaders: {
        'Content-Type' : 'application/json; charset=utf-8',
        'Accept'       : 'application/json',
        'Authorization': `Bearer ${AuthService.getToken()}`,
      },
    });

    return next.handle(req);
  }
}

You'll need to register your interceptor in the app.module as a provider:

app.module.ts

import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';
import { AuthInterceptor } from '../auth/auth.interceptor';

...

imports: [
    HttpClientModule,
    ...
],
providers: [
    {
      provide : HTTP_INTERCEPTORS,
      useClass: AuthInterceptor,
      multi   : true,
    },
    ...
],

...

You can read about this method further in this post.


Regarding the Go's side of things, this is most likely a case of mismatch between
Request Headers you're sending and the headers CORS allow.
First thing you should try is allowing all of them:

headersOk := handlers.AllowedHeaders([]string{"*"})
originsOk := handlers.AllowedOrigins([]string{"*"})
methodsOk := handlers.AllowedMethods([]string{"GET", "HEAD", "POST", "PUT", "OPTIONS"})

And if the problem goes away try carefully structuring your CORS one by one to what your client is sending.

Eyelash answered 20/11, 2017 at 21:39 Comment(2)
This worked for adding the header within the Angular app. Thanks! For the Go piece I was able to use this approach. #22453304Heindrick
Neat! Glad I could be of some help :) Good luck!Eyelash
F
33

In case you don't want to add interceptor, this worked for me:

var header = {
  headers: new HttpHeaders()
    .set('Authorization',  `Basic ${btoa(AuthService.getToken())}`)
}

this.http.get(url, header)

For Bearer,

set('Authorization',  `Bearer ${AuthService.getToken()}`)
Faus answered 2/4, 2019 at 8:15 Comment(0)
D
2

Angular 6 ==> HTTP Get request example with Authorization Header

public IsClientCreditCardExits(companyId: string, token: any) {
    let header = new Headers({ 'Authorization': `Bearer ${token}` });
    const options = new RequestOptions({
       headers: header,
    });
    return this._http.get(this.ApiURL + "api/Subscriptions/IsClientCreditCardExits/" + companyId + "/", options);    
}
Dearman answered 1/10, 2019 at 7:9 Comment(1)
RequestOptions is depricated.Crazy
B
1

Here is an example:

this.http
        .get(url, return new RequestOptions({
          headers: new Headers({
            Authorization: `Bearer ${authtoken}`
          }),
        }))
        .map(res => res.json());
Bodycheck answered 20/11, 2017 at 21:24 Comment(0)
C
1

The following example would fit a situation where you only want some headers added only when accessing resources that require authorization see code below. Kindly note that you need create the getToken method in your authentication.service.ts.

import { Injectable } from '@angular/core';
import {
  HttpInterceptor,
  HttpRequest,
  HttpHandler,
  HttpEvent
} from '@angular/common/http';
import { Observable } from 'rxjs';

import { environment } from '../../environments/environment';
import { AuthenticationService } from '../services/authentication.service';

@Injectable({
  providedIn: 'root'
})
export class AuthenticationInterceptorService implements HttpInterceptor {
  constructor(public authenticationService: AuthenticationService) {}
  intercept(
    request: HttpRequest<any>,
    next: HttpHandler
  ): Observable<HttpEvent<any>> {
    const accessToken: string = this.authenticationService.getToken();
    // set global application headers.
    request = request.clone({
      setHeaders: {
        'Content-Type': 'application/json; charset=utf-8',
        Accept: 'application/json',
        'X-AppName': environment.xAppName,
        'X-Locale': 'en'
      }
    });
    // Set headers for requests that require authorization.
    if (accessToken) {
      const authenticatedRequest = request.clone({
        headers: request.headers.set(
          'Authorization',
          `Token token=${accessToken}`
        )
      });
      // Request with authorization headers
      return next.handle(authenticatedRequest);
    } else {
      // Request without authorization header
      return next.handle(request);
    }
  }
}

Register the interceptor in app.module.ts as show below:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AuthenticationInterceptorService } from './services/authentication-interceptor.service';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';

@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule, AppRoutingModule, HttpClientModule],
  providers: [
    {
      provide: HTTP_INTERCEPTORS,
      useClass: AuthenticationInterceptorService,
      multi: true
    }
  ],
  bootstrap: [AppComponent]
})
export class AppModule {}
Chrissy answered 13/2, 2020 at 13:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.