Securing a REST API for AngularJs in Symfony

This post is a continuation of this one about setting up FOSRestBundle. The issue is that by default, the REST API that is created is accessible to anyone. For my angularjs app though, I only want the app to be able to access the API, no one else. Otherwise, external sites could hi-jack my API to get data from providers like Amazon. Since these usually have some kind of throttle on them, the API needs securing.

It turned out to be pretty straight-forward. I found the excellent Dunglas Angular CSRF bundle. Once installed, this can be used to set rules from within the security.yml file of the Symfony app, effectively securing any defined routes unless a particular cookie is included in the request. This cookie is issued from the Symfony application and then used by the AngularJs application.

The configuration

This was the configuration I used from the symfony application…

#app/config/security.yml

dunglas_angular_csrf:
 cookie:
  set_on:
   - { path: ^/$ }
   - { route: ^app_, methods: [GET, HEAD] }
 secure:
  - { path: ^/api, methods: [POST, PUT, PATCH, LINK] }
  - { route: ^sk_media_api_ }

This means that the csrf cookie is set on the root path making it available throughout the application. So, if the cookie is not present in the request sent by the angularjs application, an access denied exception will be thrown.

AngularJs application set up

This is where I’m still trying to find an ideal solution. I had originally set up the angular app using yeoman, which is a great tool to set the scaffolding up, set up bower and grunt dependencies, to use things like sass, compass and a load of cool grunt plugins that I’d never used before. However, when running the grunt task that sets up a local server, it connects on a port and isn’t connected in any way to the symfony application so doesn’t have access to its security cookie. So, none of the requests to the API actually work.

The only way I’ve found so far to make it work is to create a very minimal ‘frontend’ bundle which returns a simple view. This view has all the references to the angular application. Therefore, when the (symfony) view is rendered, the csrf cookie is generated and the angularjs app can successfully make calls to the symfony api. So now, if I try to go straight to the api url ‘http://localhost/mw/web/app_dev.php/api/mediatypes’ I get a ‘bad csrf’ error message. If my angular service calls this url using the $resource service, it works.

Next

The next thing is to expose my symfony api routes to the client-side application. One option I’ve yet to explore is using the FOSJsRoutingBundle, which is meant to expose the symfony routes to the client-side application, meaning that there is no need for hard-coded urls.

Leave a Reply