My API server runs on Lumen framework and I have a CORS middleware installed there, accompanied with a middleware which manages JSON POST data. On the server side, everything is perfect.
Now, for the UI, I use Angular 9 with Material layout. I have a pretty simple login component: it basically validates the input and then calls a service AuthService which communicates with my API server.
AuthService is pretty straightforward:
import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { BehaviorSubject, Observable, throwError } from 'rxjs';
import { catchError, map } from 'rxjs/operators';
import { HttpClient, HttpHeaders, HttpErrorResponse, HttpParams } from '@angular/common/http';
export interface Token {
token: string;
token_type: string;
expires_in: number;
}
@Injectable({
providedIn: 'root'
})
export class AuthService {
public isAuthenticated = new BehaviorSubject<boolean>(false);
constructor(
private http: HttpClient,
private router: Router
) {}
async checkAuthenticated() {
const authToken = localStorage.getItem('access_token');
return (authToken !== null);
}
getToken() {
return localStorage.getItem('access_token');
}
async login(username: string, password: string) {
const api = 'http://api.elektron.test/v1/login';
const headers = new HttpHeaders({'Content-Type': 'application/json; charset=UTF-8'});
const body = JSON.stringify({
email: username,
password
});
// tslint:disable-next-line:max-line-length
return this.http.post(api, body)
.subscribe((res: any) => {
if(res.token) {
this.isAuthenticated.next(true);
localStorage.setItem('access_token', res.token);
}
}, error => {
console.error(error);
}, () => {
console.log('etstamente');
});
}
async logout(redirect: string) {
const removeToken = localStorage.removeItem('access_token');
if (removeToken == null) {
this.isAuthenticated.next(false);
this.router.navigate([redirect]);
}
}
handleError(error: HttpErrorResponse) {
let msg = '';
if (error.error instanceof ErrorEvent) {
// client-side error
msg = error.error.message;
} else {
// server-side error
msg = `Error Code: ${error.status}\nMessage: ${error.message}`;
}
return throwError(msg);
}
}
There in the this.http.post
I can pass additional headers in the third argument, and I've tried that already, but I face the problem that whatever header I pass into it, and when I call that request, the Content-Type
is never sent.
Another idea I tried was with an interceptor:
import {HttpInterceptor, HttpRequest, HttpHandler, HttpHeaders} from '@angular/common/http';
import { AuthService } from './auth.service';
@Injectable()
export class AuthInterceptor implements HttpInterceptor {
constructor(private authService: AuthService) { }
intercept(req: HttpRequest<any>, next: HttpHandler) {
const token = this.authService.getToken();
req = req.clone({
responseType: 'json'
});
if (token) {
req = req.clone({ headers: req.headers.set('Authorization', 'Bearer ' + token) });
}
if (!req.headers.has('Content-Type')) {
req = req.clone({
setHeaders: {
'Content-Type': 'application/json',
}
});
}
// setting the accept header
req = req.clone({ headers: req.headers.set('Accept', 'application/json') });
return next.handle(req);
}
}
When it reaches any of the req.clone
statements there, I end up having behavior same as explained before for the POST
request.
So, I am clueless what I'm doing wrong here or what's causing this. In the Chrome browser, in the Console under Network tab when I try to see request headers, when these cases from above are applied, it states Provisional headers are shown - and I've found some Stack Overflow answers on that issue, but none of them solved my issue.
I've spent last 5-6 hours searching the net for a solution, tried some of my ideas, all to no avail.
EDIT: This problem is not related to Angular, but to the server and backend configuration and handling preflight requests.