Description:
I'm working with the LexikJWTAuthenticationBundle and trying to generate a JWT token with credentials sent from my Ionic2 App.
Generating the token works fine with Curl and with Postman.
curl -X POST http://localhost:8000/api/login_check -d _username=root -d _password=root
However, Ionic2 sends a preflight OPTIONS request before actually sending the POST request with the credentials. This is misunderstood by Symfony3 and sends back a 404.
Console Error From Ionic2:
OPTIONS http://localhost:8000/api/login_check 404 (Not Found) XMLHttpRequest cannot load http://localhost:8000/api/login_check.
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:8100' is therefore not allowed access. The response had HTTP status code 404.
0 - {"isTrusted":true}
EXCEPTION: 0 - {"isTrusted":true}
Question:
What must I change in my Symfony3 Application (maybe something in my routing.yml or security.yml) to not send back a 404?
Code:
Ionic2 HttpService:
@Injectable()
export class HttpService {
private baseUrl: string = "http://localhost:8000";
constructor(private http: Http){
}
public create<T>(url: string, extractData, data: any = null): Observable<Array<T>>{
let headers = new Headers({ 'Content-Type': 'application/json'});
let options = new RequestOptions({ headers: headers });
return this.http
.post(this.baseUrl + url, data, options)
.map(extractData)
.catch(this.handleError)
}
//More methods here...
}
Symfony routing.yml:
api_login_check:
path: /api/login_check
# This line is something I added to see if OPTIONS would work
# However, it did not work.
methods: [POST, OPTIONS]
Explanation:
So after a full day of breaking my head open on this issue, I found a solution. While it is possible incorporate the NelmioCorsBundle (unsure if it supports Symfony3), I find it overkill just to bypass the Cors problem.
In a real world phone application, there won't be an OPTIONS preflight request sent. This only occurs for
ionic serve
(from what I understood).The idea is to set up a Proxy Server for Ionic2.. easier said than done. There seems to be a lot of issues regarding it. I've been able to get it working though.
Solution:
There should be an
ionic.config.json
at the root directory of your Ionic2 project. You just need to add a few lines:Then simply send the request like so:
HttpService:
AuthService:
Notice I do not send JSON in my request. It currently is not supported by the bundle. However, symfony version 3.3. (I'm on 3.1.) does support it.
Breaking it down:
http://localhost:8000
http://localhost:8100
Simply states that whatever request we send out that happens to have a "/api/" in it will be converted to the proxyUrl.
For example, to generate a token, I need to send my credentials to
"/api/login_check"
.What I previously tried:
I had previously been sending the request to
http://localhost:8000/api/login_check
, which of course would send a preflight OPTIONS request causing a whole bunch of errors.I then tried specifiying simply "/api/login_check", but the http request would add
"http://localhost:8100"
infront.. my app sending a request to itself.. which of course didn't work.Solution explained:
With the proxy server up, I simply send a request to
"/api/login_check"
without anything infront, and it gets sent to my symfony3 application as aPOST request
without anypreflight OPTIONS request.
Take a look at https://github.com/nelmio/NelmioCorsBundle to at the appropriate headers. The server needs to respond with the appropriate Access-Control-Allow origin response header such as:
Access-Control-Allow-Origin: http://localhost:8100
to allow the request to succeed.
More info on CORS behavior: https://www.moesif.com/blog/technical/cors/Authoritative-Guide-to-CORS-Cross-Origin-Resource-Sharing-for-REST-APIs/