Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support to configure the Oauth2 access token location in requests #388

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Yii Framework 2 authclient extension Change Log
------------------------

- Enh #387: Use appropriate exception if client does not exist (eluhr)
- Enh #388: Added support to configure the OAuth2 access token location in requests and added a generic OAuth2 client (rhertogh)


2.2.15 December 16, 2023
Expand Down
38 changes: 35 additions & 3 deletions src/OAuth2.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
namespace yii\authclient;

use Yii;
use yii\base\InvalidConfigException;
use yii\helpers\Json;
use yii\helpers\Url;
use yii\web\HttpException;
Expand Down Expand Up @@ -37,6 +38,18 @@
*/
abstract class OAuth2 extends BaseOAuth
{
/**
* Apply the access token to the request header
* @since 2.2.16
*/
const ACCESS_TOKEN_LOCATION_HEADER = 'header';

/**
* Apply the access token to the request body
* @since 2.2.16
*/
const ACCESS_TOKEN_LOCATION_BODY = 'body';

/**
* @var string protocol version.
*/
Expand Down Expand Up @@ -71,6 +84,15 @@ abstract class OAuth2 extends BaseOAuth
*/
public $enablePkce = false;

/**
* @var string The location of the access token when it is applied to the request.
* NOTE: According to the OAuth2 specification this should be `header` by default,
* however, for backwards compatibility the default value used here is `body`.
* @since 2.2.16
*
* @see https://datatracker.ietf.org/doc/html/rfc6749#section-7
*/
public $accessTokenLocation = self::ACCESS_TOKEN_LOCATION_BODY;

/**
* Composes user authorization URL.
Expand Down Expand Up @@ -167,12 +189,22 @@ public function fetchAccessToken($authCode, array $params = [])

/**
* {@inheritdoc}
* @throws InvalidConfigException
*/
public function applyAccessTokenToRequest($request, $accessToken)
{
$data = $request->getData();
$data['access_token'] = $accessToken->getToken();
$request->setData($data);
switch($this->accessTokenLocation) {
case self::ACCESS_TOKEN_LOCATION_BODY:
$data = $request->getData();
$data['access_token'] = $accessToken->getToken();
$request->setData($data);
break;
case self::ACCESS_TOKEN_LOCATION_HEADER:
$request->getHeaders()->set('Authorization', 'Bearer ' . $accessToken->getToken());
break;
default:
throw new InvalidConfigException('Unknown access token location: ' . $this->accessTokenLocation);
}
}

/**
Expand Down
16 changes: 6 additions & 10 deletions src/OpenIdConnect.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@

namespace yii\authclient;

use Jose\Component\Core\AlgorithmManager;
use Jose\Component\Checker\AlgorithmChecker;
use Jose\Component\Checker\HeaderCheckerManager;
use Jose\Component\Core\AlgorithmManager;
use Jose\Component\KeyManagement\JWKFactory;
use Jose\Component\Signature\JWSLoader;
use Jose\Component\Signature\JWSTokenSupport;
Expand Down Expand Up @@ -76,6 +76,11 @@
*/
class OpenIdConnect extends OAuth2
{
/**
* {@inheritdoc}
*/
public $accessTokenLocation = OAuth2::ACCESS_TOKEN_LOCATION_HEADER;

/**
* @var array Predefined OpenID Connect Claims
* @see https://openid.net/specs/openid-connect-core-1_0.html#rfc.section.2
Expand Down Expand Up @@ -352,15 +357,6 @@ protected function initUserAttributes()
return $idTokenData;
}

/**
* {@inheritdoc}
*/
public function applyAccessTokenToRequest($request, $accessToken)
{
// OpenID Connect requires bearer token auth for the user info endpoint
$request->getHeaders()->set('Authorization', 'Bearer ' . $accessToken->getToken());
}

/**
* {@inheritdoc}
*/
Expand Down
5 changes: 5 additions & 0 deletions src/clients/GitHub.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@
*/
class GitHub extends OAuth2
{
/**
* {@inheritdoc}
*/
public $accessTokenLocation = OAuth2::ACCESS_TOKEN_LOCATION_HEADER;

/**
* {@inheritdoc}
*/
Expand Down
55 changes: 55 additions & 0 deletions src/clients/Oauth2Client.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php
/**
* @link https://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license https://www.yiiframework.com/license/
*/

namespace yii\authclient\clients;

use yii\authclient\OAuth2;

/**
* Generic client that allows authentication via OAuth 2.0.
*
* Example application configuration:
*
* ```php
* 'components' => [
* 'authClientCollection' => [
* 'class' => 'yii\authclient\Collection',
* 'clients' => [
* 'oauth2' => [
* 'class' => 'yii\authclient\clients\Oauth2Client',
* 'authUrl' => 'https://oauth2service.com/oauth2/authorize',
* 'tokenUrl' => 'https://oauth2service.com/oauth2/authorize',
* 'apiBaseUrl' => 'https://oauth2service.com/api',
* 'clientId' => 'your_app_client_id',
* 'clientSecret' => 'your_app_client_secret',
* 'name' => 'custom name',
* 'title' => 'custom title'
* ],
* ],
* ]
* // ...
* ]
* ```
*
* @since 2.2.16
*/
class Oauth2Client extends OAuth2
{

/**
* {@inheritdoc}
*/
public $accessTokenLocation = self::ACCESS_TOKEN_LOCATION_HEADER;

/**
* {@inheritdoc}
*/
protected function initUserAttributes()
{
return []; // Plain Oauth 2.0 doesn't specify user attributes.
}
}
15 changes: 6 additions & 9 deletions src/clients/TwitterOAuth2.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@
*/
class TwitterOAuth2 extends OAuth2
{
/**
* {@inheritdoc}
*/
public $accessTokenLocation = OAuth2::ACCESS_TOKEN_LOCATION_HEADER;

/**
* {@inheritdoc}
*/
Expand Down Expand Up @@ -64,12 +69,4 @@ protected function defaultTitle()
{
return 'Twitter';
}

/**
* {@inheritdoc}
*/
public function applyAccessTokenToRequest($request, $accessToken)
{
$request->getHeaders()->set('Authorization', 'Bearer '. $accessToken->getToken());
}
}
}
20 changes: 20 additions & 0 deletions tests/clients/FacebookTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

namespace yiiunit\extensions\authclient\clients;

use yii\authclient\clients\Facebook;
use yii\authclient\OAuth2;
use yiiunit\extensions\authclient\clients\base\BaseOauth2ClientTestCase;

class FacebookTest extends BaseOauth2ClientTestCase
{
protected function createClient()
{
return new Facebook();
}

protected function getExpectedTokenLocation()
{
return OAuth2::ACCESS_TOKEN_LOCATION_BODY;
}
}
25 changes: 25 additions & 0 deletions tests/clients/GitHubTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

namespace yiiunit\extensions\authclient\clients;

use yii\authclient\clients\GitHub;
use yii\authclient\OAuth2;
use yiiunit\extensions\authclient\clients\base\BaseOauth2ClientTestCase;

class GitHubTest extends BaseOauth2ClientTestCase
{
protected function createClient()
{
return new GitHub();
}

protected function getExpectedTokenLocation()
{
return OAuth2::ACCESS_TOKEN_LOCATION_HEADER;
}

protected function getAccessTokenHeaderTypeName()
{
return 'token';
}
}
10 changes: 8 additions & 2 deletions tests/clients/GoogleHybridTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
namespace yiiunit\extensions\authclient\clients;

use yii\authclient\clients\GoogleHybrid;
use yiiunit\extensions\authclient\TestCase;
use yii\authclient\OAuth2;
use yiiunit\extensions\authclient\clients\base\BaseOauth2ClientTestCase;
use yiiunit\extensions\authclient\traits\OAuthDefaultReturnUrlTestTrait;

class GoogleHybridTest extends TestCase
class GoogleHybridTest extends BaseOauth2ClientTestCase
{
use OAuthDefaultReturnUrlTestTrait;

Expand All @@ -15,6 +16,11 @@ protected function createClient()
return new GoogleHybrid();
}

protected function getExpectedTokenLocation()
{
return OAuth2::ACCESS_TOKEN_LOCATION_BODY;
}

/**
* Data provider for [[testDefaultReturnUrl]].
* @return array test data.
Expand Down
27 changes: 10 additions & 17 deletions tests/clients/GoogleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,27 @@
namespace yiiunit\extensions\authclient\clients;

use yii\authclient\clients\Google;
use yii\authclient\OAuth2;
use yii\authclient\OAuthToken;
use yii\authclient\signature\RsaSha;
use yiiunit\extensions\authclient\TestCase;
use yiiunit\extensions\authclient\clients\base\BaseOauth2ClientTestCase;
use yiiunit\extensions\authclient\traits\OAuthDefaultReturnUrlTestTrait;

/**
* @group google
*/
class GoogleTest extends TestCase
class GoogleTest extends BaseOauth2ClientTestCase
{
use OAuthDefaultReturnUrlTestTrait;

protected function setUp()
protected function createClient()
{
$config = [
'components' => [
'request' => [
'hostInfo' => 'http://testdomain.com',
'scriptUrl' => '/index.php',
],
]
];
$this->mockApplication($config, '\yii\web\Application');
return new Google();
}

protected function getExpectedTokenLocation()
{
return OAuth2::ACCESS_TOKEN_LOCATION_BODY;
}

public function testAuthenticateUserJwt()
Expand All @@ -45,11 +43,6 @@ public function testAuthenticateUserJwt()
$this->assertNotEmpty($token->getToken());
}

protected function createClient()
{
return new Google();
}

/**
* Data provider for [[testDefaultReturnUrl]].
* @return array test data.
Expand Down
25 changes: 25 additions & 0 deletions tests/clients/LinkedInTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

namespace yiiunit\extensions\authclient\clients;

use yii\authclient\clients\LinkedIn;
use yii\authclient\OAuth2;
use yiiunit\extensions\authclient\clients\base\BaseOauth2ClientTestCase;

class LinkedInTest extends BaseOauth2ClientTestCase
{
protected function createClient()
{
return new LinkedIn();
}

protected function getExpectedTokenLocation()
{
return OAuth2::ACCESS_TOKEN_LOCATION_BODY;
}

protected function getAccessTokenBodyParamName()
{
return 'oauth2_access_token';
}
}
20 changes: 20 additions & 0 deletions tests/clients/LiveTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

namespace yiiunit\extensions\authclient\clients;

use yii\authclient\clients\Live;
use yii\authclient\OAuth2;
use yiiunit\extensions\authclient\clients\base\BaseOauth2ClientTestCase;

class LiveTest extends BaseOauth2ClientTestCase
{
protected function createClient()
{
return new Live();
}

protected function getExpectedTokenLocation()
{
return OAuth2::ACCESS_TOKEN_LOCATION_BODY;
}
}
Loading
Loading