Last active
August 20, 2019 08:22
-
-
Save johnpancoast/359bad0255cb50ccd6ab13e4ac18e4e8 to your computer and use it in GitHub Desktop.
Example of how to use FOS OAuth Server Bundle without a client secret
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Permission to use, copy, modify, and/or distribute this software for any | |
* purpose with or without fee is hereby granted. | |
* | |
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | |
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION | |
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
*/ | |
namespace Your\Namespace\Controller; | |
use FOS\RestBundle\Controller\FOSRestController; | |
use OAuth2\OAuth2; | |
use Symfony\Component\HttpFoundation\JsonResponse; | |
use Symfony\Component\HttpFoundation\Request; | |
use Symfony\Component\HttpKernel\HttpKernelInterface; | |
use FOS\OAuthServerBundle\Controller\TokenController as FOSTokenController; | |
use Symfony\Component\Routing\RouterInterface; | |
/** | |
* Token controller to override FOS OAuth's controller | |
* | |
* This token controller mimics FOS OAuth Server Bundles except that it allows | |
* the client (app) to pass a null client secret. | |
* | |
* This is just one example of way to accomplish this while still using FOS | |
* OAuth Server Bundle. I'm sure there's another, possibly better, way of | |
* doing this but it works. | |
* | |
* Background: | |
* OAuth requires a client id and secret along with username and password for the | |
* "password" (resource owner credentials) grant type. However, mobile apps have a | |
* problem where a client secret cannot be securely shipped with them without the | |
* secret being available to everyone, thus eliminating the security that the | |
* client authentication provides. The oauth spec brings up these points but it does | |
* not make any recommendations aside from saying that you must authenticate clients. | |
* At the moment, the FOS OAuth Server Bundle has only one means of registering | |
* a client. You manually create it on the server. This is common for a lot of | |
* oauth libs, however, this means that there's currently no way to securely | |
* authenticate mobile clients because the client registration happens on the | |
* server without client interaction and the secret cannot be shipped securely | |
* with the client (app). | |
* | |
* In addition to this, the FOS OAuth Server Bundle requires the client secret to | |
* be passed (null secret not allowed) and judging by the OAuth spec, this | |
* seems like a good idea. However, without some other way to securely register and | |
* validate clients, this means that people creating oauth servers for mobile apps | |
* are left wondering what to do. Some people recommend just not passing the secret | |
* at all but the oauth spec says otherwise, for good reason. | |
* | |
* That said, if you've read the oauth spec and you're aware of the security | |
* implications of having no client authentication and you still want to use | |
* the fos oauth server bundle, you can do something like the example below. | |
* | |
* read the spec first: | |
* https://tools.ietf.org/html/rfc6749 | |
* | |
* Usage: | |
* | |
* 1.) Install/setup the fos oauth server bundle like normal. | |
* 2.) Add this controller to your codebase. | |
* 3.) Define this controller as a service. | |
* | |
* app/config/services.yml | |
* | |
* your_service_name: | |
* class: Your\Namespace\TokenController | |
* arguments: | |
* - "@fos_oauth_server.server" | |
* - "@router" | |
* - "@=container.hasParameter('oauth_clients') ? parameter('oauth_clients') : null" | |
* | |
* 4.) Define the fos oauth token route and point to your controller. | |
* | |
* app/config/routing.yml | |
* | |
* fos_oauth_server_token: | |
* path: "/oauth/v2/token" | |
* defaults: { _controller: "your_service_name:tokenAction" } | |
* methods: [GET|POST] | |
* | |
* 5.) Create your oauth client and note the id and secret. | |
* 6.) Add the client id and secret to the `oauth_clients` values in your | |
* parameters as an array (where client id is key and secret is value). | |
* | |
* app/config/parameters.yml | |
* | |
* parameters: | |
* ... | |
* oauth_clients: | |
* clientid: clientsecret | |
*/ | |
class TokenController extends FOSTokenController | |
{ | |
/** | |
* @var array | |
*/ | |
private $oauthClients = []; | |
/** | |
* @var RouterInterface | |
*/ | |
private $router; | |
/** | |
* Constructor | |
* | |
* Overrides and calls parent::__construct($server) but adds $oauthClients | |
* that are available. | |
* | |
* @param OAuth2 $server | |
* @param RouterInterface $router | |
* @param array $oauthClients | |
*/ | |
public function __construct( | |
OAuth2 $server, | |
RouterInterface $router, | |
array $oauthClients = [] | |
) | |
{ | |
$this->router = $router; | |
$this->oauthClients = $oauthClients; | |
parent::__construct($server); | |
} | |
/** | |
* Overrides parent::tokenAction() but allows no client secret. | |
* | |
* {@inheritdoc} | |
*/ | |
public function tokenAction(Request $request) | |
{ | |
$clientId = $request->get('client_id'); | |
$clientSecret = $request->get('client_secret') | |
? $request->get('client_secret') | |
: isset($this->oauthClients[$clientId]) ? $this->oauthClients[$clientId] : null | |
; | |
return parent::tokenAction( | |
Request::create( | |
$this->router->generate('fos_oauth_server_token'), | |
'POST', | |
[ | |
'client_id' => $clientId, | |
'client_secret' => $clientSecret, | |
'username' => $request->get('username'), | |
'password' => $request->get('password'), | |
'grant_type' => $request->get('grant_type'), | |
] | |
) | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment