Reputation: 904
Im trying to consume a service in a Laravel (Backend) with Angular 2. I can doit without any problem if I doit with axios
, but I need to doit with HttpClient
How can I translate this code:
const url = `${this.endPoint}/login`;
const urlCsrf = `${this.endPoint}/csrf-cookie`;
const body = { email, password };
axios.defaults.withCredentials = true;
axios.get(urlCsrf).then(() => {
axios.post(url, body).then((resp) => {
console.log(resp);
});
});
to something like this but that it works:
//this code dont work returns csrf error
this.http.get(urlCsrf).subscribe(() => {
this.http.post(url, body).subscribe((resp) => {
console.log(resp);
});
});
Upvotes: 0
Views: 616
Reputation: 101
Maybe I'm late, but I west a lot of time to find the solution for this issue and I want to share you the final solution that was correct for me.
My setup: Angular 15 - Laravel 10 with sanctum.
Laravel configuration: .env file: add lines SESSION_DRIVER=cookie SESSION_DOMAIN=localhost
sanctum.php file add stateful localhost:4200 (for angular ng serve)
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
'%s%s',
'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1,localhost:4200',
Sanctum::currentApplicationUrlWithPort()
))),
cors.php set true for credentials:
'supports_credentials' => true,
RESTART THE SERVER LARAVEL FOR APPLY CHANGES.
Then, in Angular app:
Define interceptor like:
export class HttpXsrfInterceptor implements HttpInterceptor { headerName = 'X-XSRF-TOKEN'; constructor(private tokenService: HttpXsrfTokenExtractor) {}
intercept( req: HttpRequest, next: HttpHandler ): Observable<HttpEvent> { req = req.clone({ withCredentials: true, });
req.headers.set('withCredentials', 'true');
if (req.method === 'GET' || req.method === 'HEAD') {
return next.handle(req);
}
const token = this.tokenService.getToken();
// Be careful not to overwrite an existing header of the same name.
if (token !== null && !req.headers.has(this.headerName)) {
req = req.clone({ headers: req.headers.set(this.headerName, token) });
}
return next.handle(req);
} }
In AuthService, put the login method like:
login(loginForm: LoginForm): Observable {
return this.http.get('http://localhost/sanctum/csrf-cookie').pipe( switchMap(() => {
return this.http
.post<LoginResponse>(base_url + 'access/login', loginForm)
.pipe(
tap((data) => {
const user = new User(
data.user.id,
data.user.firstname,
data.user.lastname,
data.user.username,
data.user.email,
data.user.created_at
);
this.user.next(user);
})
)
}), catchError(error => { console.error(error); return throwError(error); }) );
};
I hope this help someone.
Upvotes: 0
Reputation: 40677
That code translates to:
const body = {email, password}
this.http.get(urlCsrf).subscribe(() => {
this.http.post(url, body, { withCredentials: true }).subscribe((resp) => {
console.log(resp);
});
});
If you want to write it in a more reactive way:
const body = {email, password}
this.http.get(urlCsrf).pipe(
switchMap(()=> this.http.post(url, body, { withCredentials: true })
).subscribe((resp) => console.log(resp));
If you want to apply the withCredentials
to all requests, you should take a look at the interceptors as mentioned in the comments. A quick example:
@Injectable()
export class CredentialsInterceptor implements HttpInterceptor {
constructor() {}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(req.clone({ withCredentials: true }));
}
}
and then import it in your AppModule
providers: [
{ provide: HTTP_INTERCEPTORS, useClass: EngagementXSRFInterceptor, multi: true },
]
Upvotes: 1
Reputation: 455
I have ran to the same issue recently here is what worked for me:
$data = 'client_id=xxxxxxxxx&client_secret=xxxxxxxxx&grant_type=client_credentials';
$url = "https://xxxxxxxxxxxxxxxxxxxxx.x/xx/xxxxx";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLINFO_HEADER_OUT, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/x-www-form-urlencoded',
'Content-Length: ' . strlen($data))
);
$contents = curl_exec($ch);
if (curl_errno($ch)) {
echo curl_error($ch);
echo "\n<br />";
$contents = '';
} else {
curl_close($ch);
}
if (!is_string($contents) || !strlen($contents)) {
echo "Failed to get contents.";
$contents = '';
}
$json = json_encode($contents);
Upvotes: 1