05/01/2016 - SYMFONY
This example shows us how to create an OAuth2 API client with symfony and depends on OAuth2 API server we touched upon in previous posts so you better read up on it as well. It authenticates with client_credentials
grant type. If the API doesn't use role_hierarchy
to control controller access with @Security("has_role('xxxxx')")
in annotations, client_credentials
grant type is the best/simplest option to use. See the reference links at the bottom of the post.
In example below, I expose client_id
and client_secret
in request URI to obtain access token for demonstration purposes. You should not do that in real world applications. Instead, you should encode both of them with base64_encode
function and add it to request header as Authorization
.
$clientId = 'i-am-client-id';
$clientSecret = 'i-am-client-secret';
$base64 = base64_encode($clientId.':'.$clientSecret);
$header = 'Basic '.$base64;
So you should use it like Authorization: Basic aS1hbS1jbGllbnQtaWQ6aS1hbS1jbGllbnQtc2VjcmV0
in your request. On top of that, you should remove grant_type
from URI to send them as parameters encoded with application/x-www-form-urlencoded
. Your final request should look like the one below.
curl -X POST
-H 'Authorization: Basic aS1hbS1jbGllbnQtaWQ6aS1hbS1jbGllbnQtc2VjcmV0'
-H 'content-type: application/x-www-form-urlencoded'
-d 'grant_type=client_credentials'
http://oauth-server.dev/app_dev.php/oauth/v2/token
refresh_token
by default.access_token
doesn’t contain any "user" information association with it, therefore there can’t be any "user" information retrieved in server/API site. Only Authorization Code, Implicit Grant and Password access_token
would contain "user" information.Install "guzzlehttp/guzzle": "6.1.1"
package.
# oauth-client/app/config/parameters.yml
parameters:
oauth_api_access_token_cache_namespace: OAUTH2_ACCESS_TOKEN
oauth_api_base_url: http://oauth-server.dev/app_dev.php
oauth_api_uri_version: /1
oauth_api_token_uri: /oauth/v2/token?client_id=8_4mcij3t948isk880w0gskkksc88w0wo0wowogkgcowk4coocwk&client_secret=4gxi02iydlwkwokko4cs8w4skw8goks0s00cw00okosskcg8sg&grant_type=client_credentials
# oauth-client/src/Application/ClientBundle/Resources/config/controllers.yml
services:
application_client.controller.team:
class: Application\ClientBundle\Controller\TeamController
arguments:
- %oauth_api_access_token_cache_namespace%
- %oauth_api_base_url%
- %oauth_api_uri_version%
- %oauth_api_token_uri%
This example will generate a new access_token
per request so the requests will be slow. To solve this issue, you can store access_token
in cache and regenerate when it expired. Also putting whole logic in controller is a bad practise. You should divide it into classes like service, model, factory, helper so on.
namespace Application\ClientBundle\Controller;
use GuzzleHttp\Client;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
/**
* @Route("team", service="application_client.controller.team")
*/
class TeamController extends Controller
{
private $oauthApiAccessTokenCacheNamespace;
private $oauthApiBaseUrl;
private $oauthApiUriVersion;
private $oauthApiTokenUri;
public function __construct(
$oauthApiAccessTokenCacheNamespace,
$oauthApiBaseUrl,
$oauthApiUriVersion,
$oauthApiTokenUri
) {
$this->oauthApiAccessTokenCacheNamespace = $oauthApiAccessTokenCacheNamespace;
$this->oauthApiBaseUrl = $oauthApiBaseUrl;
$this->oauthApiUriVersion = $oauthApiUriVersion;
$this->oauthApiTokenUri = $oauthApiTokenUri;
}
/**
* @param string $name
*
* @Method({"GET"})
* @Route("/{name}")
*
* @return Response
*/
public function getTeamAction($name)
{
$accessToken = $this->getAccessToken();
$response= $this->call(
'GET',
$this->oauthApiUriVersion.'/server/team/'.$name,
$accessToken
);
return new Response($response->getBody().' with ACCESS TOKEN: '.$accessToken);
}
/**
* @param Request $request
*
* @Method({"POST"})
* @Route("")
*
* @return Response
*/
public function createTeamAction(Request $request)
{
$accessToken = $this->getAccessToken();
$response= $this->call(
'POST',
$this->oauthApiUriVersion.'/server/team',
$accessToken,
$request->getContent()
);
return new Response($response->getBody().' with ACCESS TOKEN: '.$accessToken);
}
private function getAccessToken()
{
$response = $this->call('GET', $this->oauthApiTokenUri);
$responseParts = json_decode($response->getBody(), true);
return $responseParts['access_token'];
}
private function call($method, $uri, $auth = null, $postData = null)
{
$client = new Client();
return $client->request(
$method,
$this->oauthApiBaseUrl.$uri,
[
'headers' => [
'Content-Type' => 'application/json',
'Authorization' => 'Bearer '.$auth
],
'body' => $postData
]
);
}
}
# oauth-server/src/Application/ServerBundle/Controller/ServerController.php
/**
* @param string $name
*
* @Method({"GET"})
* @Route("/team/{name}")
*
* @return Response
*/
public function getTeamAction($name)
{
return new Response(sprintf('GET your team [%s] from Server', $name));
}
/**
* @param Request $request
*
* @Method({"POST"})
* @Route("/team")
*
* @return Response
*/
public function createTeamAction(Request $request)
{
$postData = json_decode($request->getContent(), true);
return new Response(sprintf('POST your team [%s] to Server', $postData['name']));
}
# Request
GET http://oauth-client.dev/app_dev.php/team/inanzzz
# Response
GET your team [inanzzz] from Server with ACCESS TOKEN: YjQ0ZjVhMDE4MmRhMDIyYWQyMzhhODM4M2YzMGRmMzc0ODI2ZWU4NWFiMmJhZGUyOTQ0OTA3Y2MyNDhkMzYyMw
# Request
POST http://oauth-client.dev/app_dev.php/team
{
"name": "inanzzz"
}
# Response
POST your team [inanzzz] to Server with ACCESS TOKEN: ZTllODdhZTRlY2VmYzdhYmU4ZmI5MjUxMDQ1MjI0YjMzZjAxN2E3YzQxZmUwNjljMDMyZjg1OTZhODUwMGI0ZA
For more information, you can check links below.