41

My angular client is separated from the backend and I have enabled cors on the backend, everything works fine except the fact that my authentication fails because the cookie is not added to requests.

After searching online I found that I should set {withCredentials : true} on every http request. I managed to do it on a single request and it works, but not on all the requests.

I tried using BrowserXhr How to send "Cookie" in request header for all the requests in Angular2? but it doesn't work and it's also deprecated afaik.

I also tried RequestOptions but it didn't work.

What can I do to set {withCredentials: true} on every http request?

Later Edit:

@Injectable()
export class ConfigInterceptor implements HttpInterceptor {

  constructor(private csrfService: CSRFService) {

  }

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    let token = this.csrfService.getCSRF() as string;
    const credentialsReq = req.clone({withCredentials : true, setHeaders: { "X-XSRF-TOKEN": token } });
    return next.handle(credentialsReq);
  }
}
Koray Tugay
  • 22,894
  • 45
  • 188
  • 319
exilonX
  • 1,712
  • 3
  • 26
  • 50

2 Answers2

51

You can use an HttpInterceptor.

@Injectable()
export class CustomInterceptor implements HttpInterceptor {

    constructor() {
    }

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

        request = request.clone({
            withCredentials: true
        });

        return next.handle(request);
    }
}

Next you have to provide it:

@NgModule({
  bootstrap: [AppComponent],
  imports: [...],
  providers: [
    {
      provide: HTTP_INTERCEPTORS,
      useClass: CustomInterceptor ,
      multi: true
    }
  ]
})
export class AppModule {}

Source and full explanation

Alexei - check Codidact
  • 22,016
  • 16
  • 145
  • 164
Venomy
  • 2,076
  • 15
  • 25
  • 1
    Please [avoid link only answers](http://meta.stackoverflow.com/tags/link-only-answers/info). Answers that are "barely more than a link to an external site” [may be deleted](http://stackoverflow.com/help/deleted-answers). – Quentin Nov 15 '17 at 11:01
  • 2
    @Quentin Apologies, I updated my answer with code examples. – Venomy Nov 15 '17 at 12:03
  • 1
    Note that this only works if you're doing requests with @angular/common/http, not with @angular/http. – Thomas Wana Jan 02 '18 at 12:51
  • This only appears to work for get requests, any advice on post and put? – MGDavies May 01 '18 at 16:00
  • @MGDavies The `HttpInterceptor` is not limited to `GET` requests and should also work for `POST` and `PUT`. – Venomy May 02 '18 at 12:27
  • @ThomasWana Do you know how I could add that functionality with @angular/http? – Phil Jul 06 '18 at 22:06
0

Another perhaps more simple way is to create your own ApiService. It would use an injected HttpClient. All XHR requests would use the ApiService instead of HttpClient directly.

Here is an example implementation:

https://github.com/gothinkster/angular-realworld-example-app/blob/63f5cd879b5e1519abfb8307727c37ff7b890d92/src/app/core/services/api.service.ts

Some of the code that I have modified:

@Injectable()
export class ApiService {

  private httpOptions = {
    headers: new HttpHeaders({ 'Content-Type': 'application/json' }),
    withCredentials: true // to allow cookies to go from "https://localhost:4567" to "http://localhost:5678"
  };

  constructor(
    private http: HttpClient
  ) { }

  private formatErrors(error: any) {
    return throwError(error.error);
  }

  get(path: string, params: HttpParams = new HttpParams()): Observable<any> {
    return this.http.get(`${environment.api_url}${path}`, { params })
      .pipe(catchError(this.formatErrors));
  }

  put(path: string, body: Object = {}): Observable<any> {
    return this.http.put(
      `${environment.api_url}${path}`,
      JSON.stringify(body),
      this.httpOptions
    ).pipe(catchError(this.formatErrors));
  }

  post(path: string, body: Object = {}): Observable<any> {
    return this.http.post(
      `${environment.api_url}${path}`,
      JSON.stringify(body),
      this.httpOptions
    ).pipe(catchError(this.formatErrors));
  }
Jess
  • 23,901
  • 21
  • 124
  • 145