I am creating a simple cakephp backend. For the frontend I am using angular. Angular connects through an api route (using ADmad JWT plugin) to the backend and should log in to get a token.
My Api/UsersController.php
public function token()
{
$user = $this->Auth->identify();
if (!$user) {
throw new UnauthorizedException('Invalid username or password');
}
$this->set([
'success' => true,
'data' => [
'token' => JWT::encode(
[
'sub' => $user['id'],
'exp' => time() + 604800
],
Security::salt()
)
],
'_serialize' => ['success', 'data']
]);
}
Now when I want to test my connection with Postman, (with following options) it works:
Request-Type: POST
URL: http://cake3api.app/api/users/token.json
Headers: Accept => application/vnd.api+json
Content-Type => application/vnd.api+json
Body (JSON array):
{
"username":"test",
"password":"1234"
}
Answer:
{
"success": true,
"data": {
"token": "HERE_COMES_THE_TOKEN_AS_ANSWER"
}
}
Now I want to use this auth-api with Angular4. I created an AuthService, so I can make a promise to the cake-api:
import { Injectable } from '@angular/core';
import { Headers, Http } from '@angular/http';
import 'rxjs/add/operator/toPromise';
@Injectable()
export class AuthService {
private BASE_URL: string = 'http://cake3api.app/api/users';
private headers: Headers = new Headers({
'Content-Type' : 'application/vnd.api+json',
'Accept' : 'application/vnd.api+json'
});
constructor(private http: Http) { }
login(user): Promise<any> {
let url: string = `${this.BASE_URL}/token.json`;
return this.http.post(url, user, {headers: this.headers}).toPromise();
}
}
And I'm calling the service in my LoginComponent
import { Component, OnInit } from '@angular/core';
import { AuthService } from '../../services/auth.service';
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
constructor(private auth: AuthService) { }
ngOnInit(): void {
let sampleUser: any = {
username: 'test' as string,
password: '1234' as string
};
this.auth.login(sampleUser).then((user) => {
console.log(user.json());
}).catch((err) => {
console.log(err);
});
}
}
With this, I receive following:
OPTIONS http://cake3api.app/api/users/token.json 401 (Unauthorized)
Failed to load http://cake3api.app/api/users/token.json: Response for preflight has invalid HTTP status code 401
// XHR Request & Response (from console)
**GENERAL**
Request URL:http://cake3api.app/api/users/token.json
Request Method:OPTIONS
Status Code:401 Unauthorized
Remote Address:127.0.0.1:80
Referrer Policy:no-referrer-when-downgrade
**RESPONSE HEADERS**
Access-Control-Allow-Headers:origin, x-requested-with, content-type
Access-Control-Allow-Methods:PUT, GET, POST, DELETE, OPTIONS
Access-Control-Allow-Origin:*
Connection:Keep-Alive
Content-Length:247
Content-Type:application/json; charset=UTF-8
Date:Fri, 27 Oct 2017 08:56:17 GMT
Keep-Alive:timeout=5, max=100
Server:Apache/2.4.27 (Win32) OpenSSL/1.0.2l PHP/7.1.9
X-DEBUGKIT-ID:ac7b0f38-4c97-44d4-8c26-9f95b94ce937
X-Powered-By:PHP/7.1.9
**REQUEST HEADERS**
Accept:*/*
Accept-Encoding:gzip, deflate
Accept-Language:de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4,bs;q=0.2
Access-Control-Request-Headers:content-type
Access-Control-Request-Method:POST
Cache-Control:no-cache
Connection:keep-alive
Host:cake3api.app
Origin:http://localhost:4200
Pragma:no-cache
Referer:http://localhost:4200/login
User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36
Anyone got an idea, why this constellation is not working? My thoughts are, that angular is not sending the request as it should (wrong headers sent?). The weird thing is, that my tests with postman worked, but not with angular.
If someone thinks it's because cake does not accept the ORIGIN header, it should. I enabled the access-control in it's ./.htaccess
<IfModule mod_headers.c>
Header set Access-Control-Allow-Origin "*"
Header add Access-Control-Allow-Headers "origin, x-requested-with, content-type"
Header add Access-Control-Allow-Methods "PUT, GET, POST, DELETE, OPTIONS"
</IfModule>
EDIT
Because the problem seems to be with the browser sending OPTIONS-request, I made a bypass, but still not working.
RewriteEngine On
RewriteCond %{REQUEST_METHOD} OPTIONS
RewriteRule ^(.*)$ $1 [R=200,L]
The error message disappears, but a new one came:
Failed to load http://cake3api.app/api/users/token.json: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:4200' is therefore not allowed access.
Now it says that the header Access-Control-Allow-Origin is not set. But I already set it in the same .htaccess file where I put the OPTIONS-request workaround. What a disturbing problem, already lost a lot of time for such small things...

chrome.exe --user-data-dir="C:/ChromeDevSession" --disable-web-security- Matt Backslash