Authenticate with OAuth2 client_credentials in Symfony2 Authenticate with OAuth2 client_credentials in Symfony2 symfony symfony

Authenticate with OAuth2 client_credentials in Symfony2


I spend a day struggling with the same situation (also Symfony 3). In the end the solution was quite simple for me.

In my security.yml I defined the following:

firewalls:    # disables authentication for assets and the profiler, adapt it according to your needs    dev:        pattern: ^/(_(profiler|wdt)|css|images|js)/        security: false    main:        anonymous: ~        # activate different ways to authenticate        # http_basic: ~        # http://symfony.com/doc/current/book/security.html#a-configuring-how-your-users-will-authenticate        # form_login: ~        # http://symfony.com/doc/current/cookbook/security/form_login_setup.html    oauth_token:        pattern:    ^/oauth/v2/token        security:   false    oauth_authorize:        pattern:    ^/oauth/v2/auth        # Add your favorite authentication process here        form_login:            provider: userprovider            check_path: /oauth/v2/auth_login_check            login_path: /oauth/v2/auth_login        #anonymous: true #allow all requests    api:        pattern:    ^/api        fos_oauth:  true        stateless:  true        anonymous:  falseaccess_control:    - { path: ^/oauth/v2/token, roles: [ IS_AUTHENTICATED_ANONYMOUSLY, IS_AUTHENTICATED_FULLY ] }    - { path: ^/api, roles: [ IS_AUTHENTICATED_FULLY ] }

There was a little error in there. I left the main in the firewall open for all urls:

  main:        anonymous: ~        # activate different ways to authenticate

By removing the main and its childeren or defining a proper "pattern" which does not override the pattern of the api firewall, my OAuth2 server was working correctly.

Later I found out that the order of the firewalls is very important. Simply defining the API firewall rules before the main(default) firewall rules works like a charm. So the following is correct:

firewalls:    # disables authentication for assets and the profiler, adapt it according to your needs    dev:        pattern: ^/(_(profiler|wdt)|css|images|js)/        security: false    oauth_token:        pattern:    ^/oauth/v2/token        security:   false    oauth_authorize:        pattern:    ^/oauth/v2/auth        # Add your favorite authentication process here        form_login:            provider: userprovider            check_path: /oauth/v2/auth_login_check            login_path: /oauth/v2/auth_login        #anonymous: true #allow all requests    api:        pattern:    ^/api        fos_oauth:  true        stateless:  true        anonymous:  false    main:        anonymous: ~        # activate different ways to authenticate        # http_basic: ~        # http://symfony.com/doc/current/book/security.html#a-configuring-how-your-users-will-authenticate        # form_login: ~        # http://symfony.com/doc/current/cookbook/security/form_login_setup.htmlaccess_control:    - { path: ^/oauth/v2/token, roles: [ IS_AUTHENTICATED_ANONYMOUSLY, IS_AUTHENTICATED_FULLY ] }    - { path: ^/api, roles: [ IS_AUTHENTICATED_FULLY ] }


I figured out a way to authenticate inside the controller but I am not sure if this is the best way to accomplish what I want. It seems like FOSOAuthServerBundle should be able to do all these checks for me.

<?phpnamespace ApiBundle\Controller;use Symfony\Bundle\FrameworkBundle\Controller\Controller;use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;use Symfony\Component\HttpFoundation\Request;use Symfony\Component\Security\Core\Exception\TokenNotFoundException;use Symfony\Component\Security\Core\Exception\AuthenticationExpiredException;use FOS\OAuthServerBundle\Security\Authentication\Token\OAuthToken;use Symfony\Component\HttpFoundation\JsonResponse;class UserApiController extends Controller{    /**     * @Route("/user", name="user")     */    public function indexAction(Request $request)    {        $authenticationErrorResponse = $this->checkAuthAndGetErrorResponse($request);        if ($authenticationErrorResponse) {            return $authenticationErrorResponse;        }        // all good, now do something    }    private function checkAuthAndGetErrorResponse(Request $request)    {        $tokenManager = $this->get('fos_oauth_server.access_token_manager.default');        $bearerToken = $this->get('fos_oauth_server.server')->getBearerToken($request);        if (!$bearerToken) {            return new JsonResponse(['status' => 400, 'message' => 'Bearer token not supplied'], 400);        }        $accessToken = $tokenManager->findTokenByToken($bearerToken);        if (!$accessToken) {            return new JsonResponse(['status' => 400, 'message' => 'Bearer token not valid'], 400);        }        if ($accessToken->hasExpired()) {            return new JsonResponse(['status' => 400, 'message' => 'Access token has expired'], 400);        }        // may want to validate something else about the client, but that is beyond OAuth2 scope        //$client = $accessToken->getClient();        return null;    }}