Home > OpenID Connect OAuth Server by DnC > Develop > OAuthSD Service for Lusitanian/PHPoAuthLib

OAuthSD Service for Lusitanian/PHPoAuthLib

The Lusitanian / PHPoAuthLib library provides oAuth support in PHP and is very easy to integrate into any project requiring an OAuth 2 client.

This article presents the OAuthSD service code to include in the library.


If the Oauthsd class is not provided by a plugin or an extension, the code below must be inserted in the library at the location and under the specified name:

... /vendor/Lusitanian/oauth/src/OAuth/OAuth2/ Service/Oauthsd.php

Notes:
- The scope openid indicates that we use the layer OpenID Connect.
- ’response_type’ => ’code’ indicates that we are using the Authorization Code Flow.
- The scope "sli" allows (in particular) the single connection.
- For a simple SSO use, it is useless to risk revealing the user’s data with the scope profile. By deleting the scope profile, OAuthSD will use the default scope basic, and only the sub (subject) field will be returned by the authentication request.
PHP

  1. <?php
  2. /**  
  3. * OpenID Connect Authentication with Oauthsd
  4. * @link     https://oa.dnc.global
  5. * Oauthsd.php OAuth service for the Lusitanian PHPoAuthLib
  6. * @link     https://github.com/Lusitanian/PHPoAuthLib
  7. * @author   Bertrand Degoy bertrand@degoy.com
  8. * @copyright (c) 2018 B.Degoy DnC https://degoy.com
  9. * @license  http://www.opensource.org/licenses/mit-license.html MIT License
  10. */
  11.  
  12. //dnc4
  13.  
  14. namespace OAuth\OAuth2\Service;
  15.  
  16. use OAuth\OAuth2\Token\StdOAuth2Token;
  17. use OAuth\Common\Http\Exception\TokenResponseException;
  18. use OAuth\Common\Http\Uri\Uri;
  19. use OAuth\Common\Consumer\CredentialsInterface;
  20. use OAuth\Common\Http\Client\ClientInterface;
  21. use OAuth\Common\Storage\TokenStorageInterface;
  22. use OAuth\Common\Http\Uri\UriInterface;
  23.  
  24.  
  25. class Oauthsd extends AbstractService
  26. {
  27.  
  28.     /**
  29.     * Available scopes (will be tested by AbstractService).
  30.     * Might be larger than those defined by client application.
  31.     * @link https://oa.dnc.global/-Sujets-communs-.html#definitionetgestiondesscopesdansOAuthsd
  32.     * @see  #attributes
  33.     */
  34.     const SCOPE_OPENID           = 'openid';
  35.     const SCOPE_PROFILE          = 'profile';
  36.     const SCOPE_EMAIL            = 'email';
  37.     const SCOPE_ADDRESS          = 'address';
  38.     const SCOPE_PHONE            = 'phone';
  39.     const SCOPE_SLI              = 'sli';
  40.  
  41.     public function __construct(
  42.         CredentialsInterface $credentials,
  43.         ClientInterface $httpClient,
  44.         TokenStorageInterface $storage,
  45.         $scopes = array(),
  46.         UriInterface $baseApiUri = null
  47.     ) {
  48.  
  49.         $scopes = array_merge($scopes, array(openid, sli, profile));   // profile ???
  50.  
  51.         parent::__construct($credentials, $httpClient, $storage, $scopes, $baseApiUri);
  52.  
  53.         if (null === $baseApiUri) {
  54.             $this->baseApiUri = new Uri('https://oa.dnc.global/');
  55.         }
  56.     }
  57.  
  58.     /**
  59.     * Override abstract function in order to provide required parameters in authorization request.
  60.     * State is required by OAuthSD
  61.     * Scopes :
  62.     * openid is required by OpenID Connect, sli is particular to OAuthSD, basic is enough for phpBB.
  63.     * @link https://oa.dnc.global/-Sujets-communs-.html#definitionetgestiondesscopesdansOAuthsd
  64.     */
  65.     public function getAuthorizationUri(array $additionalParameters = array())
  66.     {
  67.         $parameters = array_merge(
  68.             $additionalParameters,
  69.             array(
  70.                 //'type'          => 'web_server',
  71.                 'client_id'     => $this->credentials->getConsumerId(),
  72.                 'redirect_uri'  => $this->credentials->getCallbackUrl(),
  73.                 'response_type' => 'code',
  74.                 'scope'         => 'openid sli',    // do not mention basic.      
  75.             )
  76.         );
  77.  
  78.         if (!isset($parameters['state'])) {
  79.             $parameters['state'] = $this->generateAuthorizationState();
  80.         }
  81.         $this->storeAuthorizationState($parameters['state']);
  82.  
  83.         // Build the url
  84.         $url = clone $this->getAuthorizationEndpoint();
  85.         foreach ($parameters as $key => $val) {
  86.             $url->addToQuery($key, $val);
  87.         }
  88.         return $url;
  89.     }
  90.  
  91.     /**
  92.     * {@inheritdoc}
  93.     */
  94.     public function getAuthorizationEndpoint()
  95.     {
  96.         return new Uri('https://oa.dnc.global/authorize');
  97.     }
  98.  
  99.     /**
  100.     * {@inheritdoc}
  101.     */
  102.     public function getAccessTokenEndpoint()
  103.     {
  104.         return new Uri('https://oa.dnc.global/token');
  105.     }
  106.  
  107.     /**
  108.     * {@inheritdoc}
  109.     */
  110.     protected function getAuthorizationMethod()
  111.     {
  112.         return static::AUTHORIZATION_METHOD_HEADER_BEARER;        // ou AUTHORIZATION_METHOD_QUERY_STRING ???
  113.     }
  114.  
  115.     /**
  116.     * {@inheritdoc}
  117.     */
  118.     protected function parseAccessTokenResponse($responseBody)
  119.     {
  120.         $data = json_decode($responseBody, true);
  121.  
  122.         if (null === $data || !is_array($data)) {
  123.             throw new TokenResponseException('Unable to parse response.');
  124.         } elseif (isset($data['message'])) {
  125.             throw new TokenResponseException('Error in retrieving token: "' . $data['message'] . '"');
  126.         } elseif (isset($data['name'])) {
  127.             throw new TokenResponseException('Error in retrieving token: "' . $data['name'] . '"');
  128.         }
  129.  
  130.         $token = new StdOAuth2Token();
  131.         $token->setAccessToken($data['access_token']);
  132.         $token->setLifeTime($data['expires_in']);
  133.  
  134.         if (isset($data['refresh_token'])) {
  135.             $token->setRefreshToken($data['refresh_token']);
  136.             unset($data['refresh_token']);
  137.         }
  138.  
  139.         unset($data['access_token']);
  140.         unset($data['expires_in']);
  141.  
  142.         $token->setExtraParams($data);
  143.  
  144.         return $token;
  145.     }
  146.  
  147.     /**
  148.     * {@inheritdoc}
  149.     */
  150.     public function requestAccessToken($code, $state = null)
  151.     {
  152.         if (null !== $state) {
  153.             $this->validateAuthorizationState($state);
  154.         }
  155.  
  156.         $bodyParams = array(
  157.             'code'          => $code,
  158.             'client_id'     => $this->credentials->getConsumerId(),
  159.             'client_secret' => $this->credentials->getConsumerSecret(),
  160.             'redirect_uri'  => $this->credentials->getCallbackUrl(),
  161.             'grant_type'    => 'authorization_code',
  162.         );
  163.  
  164.         $responseBody = $this->httpClient->retrieveResponse(
  165.             $this->getAccessTokenEndpoint(),
  166.             $bodyParams,
  167.             $this->getExtraOAuthHeaders()
  168.         );
  169.        
  170.         $token = $this->parseAccessTokenResponse($responseBody);
  171.         $this->storage->storeAccessToken($this->service(), $token);
  172.  
  173.         return $token;
  174.     }
  175. }

Download

Roadmap

In a corporate realm, you want to have your own OIDC server and get Userinfo data in a specific format, usually using an existing user base.
For that, it would be necessary:
- a setter function for the URL of the OIDC server in order to be able to choose the authentication server.
- a setter function to configure the Userinfo data.
- this should lead to a universal OpenID Connect client. Then try a pull request to lusitanian?