Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular HttpClient not setting Authorization header [duplicate]

Tags:

http

angular

I have seen several other questions like this, but they do not solve the issue. I used MailChimp's API to make a simple call to add a member to my mailing list when they sign up.

However when I test, I get a 401 unauthorized and the API complains of no API key submitted. When I inspect the request in Chrome, I don't see any Authorization header. Here is my code:

        const formData = {
            email_address: this.emailControl.value,
            status: 'subscribed',
            merge_fields: {
                NAME: this.nameControl.value
            }
        };
        const header = new HttpHeaders({
            'Authorization': 'apikey:' + environment.mailChimpApiKey
        });

        this.http.post(this.mailChimpUrl, formData, {
            headers: header,
            observe: 'response'
        }).subscribe(response => {
            console.log('response', response);
            if (response.status === 200) {
                this.submitted = true;
            }
        });

I have checked and double-checked the HttpClient.post method signature, and how the MailChimp API expects to receive the Auth header. It seems like I'm doing everything right, so why isn't Angular setting the header?

I am noticing that the value changes only for the Access-Control-Request-Headers when I set optional headers. Am I reading the chrome console wrong?

enter image description here

Angular version: 5.2.4

like image 925
inorganik Avatar asked Mar 19 '18 15:03

inorganik


2 Answers

The issue is not with Angular. Modern browsers send a preflight OPTIONS request for most cross-domain requests, which is not supported by Mailchimp. The Mailchimp API does not support client-side implementations:

MailChimp does not support client-side implementation of our API using CORS requests due to the potential security risk of exposing account API keys.

It would have been nice if this was stated a bit more obviously, but I didn't notice it at first. The best solution is to use jsonp.

like image 134
inorganik Avatar answered Oct 18 '22 03:10

inorganik


To do this we need to import Headers and RequestOptions along with Http from @angular/http library.

And as @Maciej suggested you can also use withCredentials : true to your request options.

ApplicationService.ts

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

@Injectable()
export class ApplicationService {

  constructor(private http: Http) {
  }

  myformPost(id:number, formData : any){

     let header = this.initHeaders();
     let options = new RequestOptions({ headers: header, method: 'post'});
     let body = JSON.stringify(formData);

     return this.http.post(this.myapiUrl, body, options)
                .map(res => {
                    return res.json();
                })
                .catch(this.handleError.bind(this));
  }

  private initHeaders(): Headers {
      var headers = new Headers();
      let token = localstorage.getItem(StorageKey.USER_TOKEN);
      if (token !== null) {
         headers.append('Authorization', token);
      }

      headers.append('Pragma', 'no-cache');
      headers.append('Content-Type', 'application/json');
      headers.append('Access-Control-Allow-Origin', '*');
      return headers;
  }

  private handleError(error: any): Observable<any> {
      return Observable.throw(error.message || error);
  }             
}
like image 34
Amol Bhor Avatar answered Oct 18 '22 03:10

Amol Bhor