1

I have a symfony 2 backend and I have installed it on a server. My frontend is an ionic PWA, so it runs in browser and it is also installed on that server, but with an other subdomain. When I send a request from the web app to the backend, I'm getting this error:

OPTIONS https://api.example.com/api/login.json

XMLHttpRequest cannot load https://api.example.com/api/login.json. Response for preflight has invalid HTTP status code 405

This is my code for the login action:

/**
 * Login via username and password or via API key
 *
 * @Doc\ApiDoc(
 *  section="Security",
 *  description="Login",
 *  views={"default", "security"}
 * )
 *
 * @param ParamFetcher $params
 *
 * @Rest\RequestParam(name="username", nullable=true, description="Username")
 * @Rest\RequestParam(name="password", nullable=true, description="Password")
 * @Rest\RequestParam(name="apikey", nullable=true, description="API key (alternative to username + password)")
 *
 * @Rest\Post("/login", name="api_security_login", options={"method_prefix" = false})
 *
 * @return Response
 */
public function loginAction(ParamFetcher $params)
{
    //...do some stuff here...//

    $data = array(
        'user'   => $userValue,
        'apikey' => $user->getApiKey(),
    );

    $groups = array('default', 'private');

    return $this->createAPIResponse(self::STATUS_OK, $data, $groups);
}

This is header from the response:

Access-Control-Allow-Methods:GET,POST,OPTIONS,DELETE,PUT
Access-Control-Allow-Origin:*
Allow:POST
Cache-Control:no-cache
Connection:Keep-Alive
Content-Length:54
Content-Type:application/json
Date:Tue, 29 Aug 2017 08:33:26 GMT
Keep-Alive:timeout=5, max=100
Server:Apache

This is the error message in the prod.log file:

request.ERROR: Uncaught PHP Exception Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException: "No route found for "OPTIONS /api/login.json": Method Not Allowed (Allow: POST)" at /var/www/example.com/api/htdocs/symfony/vendor/symfony/symfony/src/Symfony/Component/HttpKernel/EventListener/RouterListener.php line 163 {"exception":"[object] (Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException(code: 0): No route found for \"OPTIONS /api/login.json\": Method Not Allowed (Allow: POST) at /var/www/example.com/api/htdocs/symfony/vendor/symfony/symfony/src/Symfony/Component/HttpKernel/EventListener/RouterListener.php:163, Symfony\Component\Routing\Exception\MethodNotAllowedException(code: 0): at /var/www/example.com/api/htdocs/symfony/app/cache/prod/appProdUrlMatcher.php:855)"} []

So it seems like the OPTIONS request, which is send because CORS, is not allowed, because of the "Allow" header, where only "POST" is allowed. So what is the best way to fix that for all routes?

aynber
  • 22,380
  • 8
  • 50
  • 63
Nono
  • 1,073
  • 4
  • 23
  • 46

2 Answers2

3

You only have a route on your action for the POST method:

@Rest\Post("/login", name="api_security_login", options={"method_prefix" = false})

If you want to answer OPTIONS requests, you have to define an Options route using the @Rest\Options annotation.

You can either have several annotations on the same action and test the method inside the action (typically the case with GET and POST for a form action), or define two distinct actions with the same path but different methods.

http://symfony.com/doc/master/bundles/FOSRestBundle/7-manual-route-definition.html

  • Already tried it with ```@Rest\Options("/login", name="api_security_login_options", options={"method_prefix" = false})``` below the Post, but still the same problem – Nono Aug 29 '17 at 09:00
0

There is no route that accepts the options http method.

No route found for "OPTIONS /api/login.json"

You need to define it first:

/**
 * @Rest\Route(
 *   "/login", 
 *   name="api_security_login",
 *   methods = { 
 *     Request::METHOD_POST,
 *     Request::METHOD_OPTIONS,
 *   }
 * )
 */

Clear your cache afterwards and verify that the route is active i.e. using:

bin/console debug:router | grep -i api_security_login
Nicolai Fröhlich
  • 51,330
  • 11
  • 126
  • 130
  • It's neither working for me. And even if it should, I have to edit every route... But it seems like there is no simple way for it. – Nono Aug 29 '17 at 09:25
  • You asked why your route is not working and the answer is clearly "because it doesn't exist" as we can see from the exception thrown by symfony. No CORS issue involved. What's the output of `bin/console debug:router | grep -i api_security_login` after you applied my suggested changes? – Nicolai Fröhlich Aug 29 '17 at 09:45
  • I suggest we first find out what is not working for a single `OPTIONS` request. then we allow the options method for all your controller actions / routes. There's a simple way but I'm not able to help you if you just say **it's neither working for me** and you don't provide any information about your application's behavior, exception messages or command-output after you applied the changes. – Nicolai Fröhlich Aug 29 '17 at 09:55
  • But the OPTIONS request is send because of CORS, I don't send it on my own. And I don't understand why there is no simple way to accept the request for every route and response to it with whatever should be answered to it. ... I have just added your code to the comment block. Or do I have to replace it for the Post annotation? Because now I have "loginapi_security_login" with "POST|OPTIONS" and "api_security_login" with "POST". – Nono Aug 29 '17 at 09:57
  • You need to remove the `@Rest\Post` annotation and replace it with `@Rest\Route` .... or add `@Rest\Options` but then you'd need to use a different name for the route because otherwise the `POST` route would be overriden. – Nicolai Fröhlich Aug 29 '17 at 10:10
  • I have replaced it, now I'm getting ```XMLHttpRequest cannot load https://api.example.com/api/login.json. Response for preflight has invalid HTTP status code 401``` and in the symfony logs: ... "You are not authenticated" ... – Nono Aug 29 '17 at 10:10
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/153116/discussion-between-nono-and-nifr). – Nono Aug 29 '17 at 10:11
  • Now you have a different issue which is related to your authentication process. Your original issue regarding the `OPTIONS` method was resolved. – Nicolai Fröhlich Aug 29 '17 at 10:11