Angular HttpClient post not working

Viewed 20170

I'm changing my code to change my http api from '@angular/http' to '@angular/common/http'. Most of my requests are working fine, but the authentication that brings me the refresh token isn't working, no matter how hard I try.... Please, seem my code bellow:

    const headerHttp = new HttpHeaders();
    headerHttp.set('Content-Type', 'application/x-www-form-urlencoded');
    headerHttp.set('Authorization', 'Basic YW5ndWxhcjphbmd1bGFy');

    this.clientHttp.post(this.oauthTokenUrl,
      { username: user, password: pwd , grant_type: 'password' },
      {  headers: headerHttp, withCredentials: true })
        .subscribe(
      res => {
         console.log(res);
      },
      err => {
         console.log('Error occured');
      }
    );

But the parameters ( username, password and grant_type ) aren't being reaching the server and an input screen is popping.

enter image description here

This is my the result of my request that works, with '@angular/http':

IMAGE 1 enter image description here

This is the result of my request that doesn't work, which code I put above.

IMAGE 2 enter image description here

EDIT 1 - The authentication input screen isn´t popping up anymore with the code bellow.

const _params = new HttpParams()
.set('grant_type', 'password')
.set('username', usuario)
.set('password', senha );

const _headers = new HttpHeaders()
  .set('Authorization', 'Basic YW5ndWxhcjphbmd1bGFy')
  .set('Content-Type', 'application/x-www-form-urlencoded');

const httpOptions = {
  headers: _headers,
  params: _params,
  withCredentials: true
};

this.clientHttp.post<String>(this.oauthTokenUrl, httpOptions).subscribe(
res => {
  console.log(res);
},
err => {
  console.log('Error occurred', err);
});

THIS is what my code used to be, and work Ok.

    const headers = new Headers();

    headers.append('Content-Type', 'application/x-www-form-urlencoded');
    headers.append('Authorization', 'Basic YW5ndWxhcjphbmd1bGFy');

    const body = `username=${usuario}&password=${senha}&grant_type=password`;

    return this.http.post(this.oauthTokenUrl, body,
        { headers, withCredentials: true })
      .toPromise()
      .then(response => {
        this.armazenarToken(response.json().access_token);
      })
      .catch(response => {
        if (response.status === 400) {
          const responseJson = response.json();

          if (responseJson.error === 'invalid_grant') {
            return Promise.reject('Usuário ou senha inválida!');
          }
        }

        return Promise.reject(response);
      });
  }

But now the HttpClient creates a "Request Payload" instead of a "Form Data". Why? The servlet cannot read "Request Payload" the same way he used to read "Form Data", so it doesn't do the authentication properly.

EDIT 2 - The Solution

After a ton of tries, what make it work was a new FormData() that I put following @mtpultz suggestion.

const params = new HttpParams()
.set('grant_type', 'password')
.set('username', user)
.set('password', pwd );

const headers = new HttpHeaders()
  .set('Authorization', 'Basic xpto')
  .set('Content-Type', 'application/x-www-form-urlencoded');

const httpOptions = {
  headers: headers,
  params: params,
  withCredentials: true
};

//The line works ( Requisition with Form Data, like IMAGE 1 above )
this.httpClient.post<Response>(this.oauthTokenUrl,  new FormData(), httpOptions )

//The line, without new FormData(), doesn't work.  ( Requisition with Request Payload, like IMAGE 2 above )
this.httpClient.post<Response>(this.oauthTokenUrl,  httpOptions )
1 Answers

Putting your code into a stackblitz example this seems to send Form Data and not as Request Payload when you view it in the console. The reason it sends properly I believe is based on native forms submitting form field name/values pairs as a query-string, which adding them as params mimics.

  public test() {
    const headers = new HttpHeaders({
      'Content-Type': 'application/x-www-form-urlencoded',
      'Authorization': 'Basic YW5ndWxhcjphbmd1bGFy'
    });
    const params = new HttpParams()
      .set('username', 'test@example.com')
      .set('password', 'secret')
      .set('grant_type', 'password');
    const options = {
      headers,
      params,
      withCredentials: true
    };
    this.httpClient.post('https://reqres.in/api/example', null, options)
      .subscribe(response => console.log(response));
  }

Also, I'd suggest using Observables and not converting your responses to Promises. If you're not comfortable with Observables yet it won't take long to learn some basics just to handle HTTP requests.

Related