Skip to content

Commit b9f753f

Browse files
authored
Fix #388: Added support to configure the OAuth2 access token location in requests and added a generic OAuth2 client
1 parent 1677120 commit b9f753f

18 files changed

+391
-41
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Yii Framework 2 authclient extension Change Log
55
------------------------
66

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

910

1011
2.2.15 December 16, 2023

src/OAuth2.php

+35-3
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
namespace yii\authclient;
99

1010
use Yii;
11+
use yii\base\InvalidConfigException;
1112
use yii\helpers\Json;
1213
use yii\helpers\Url;
1314
use yii\web\HttpException;
@@ -37,6 +38,18 @@
3738
*/
3839
abstract class OAuth2 extends BaseOAuth
3940
{
41+
/**
42+
* Apply the access token to the request header
43+
* @since 2.2.16
44+
*/
45+
const ACCESS_TOKEN_LOCATION_HEADER = 'header';
46+
47+
/**
48+
* Apply the access token to the request body
49+
* @since 2.2.16
50+
*/
51+
const ACCESS_TOKEN_LOCATION_BODY = 'body';
52+
4053
/**
4154
* @var string protocol version.
4255
*/
@@ -71,6 +84,15 @@ abstract class OAuth2 extends BaseOAuth
7184
*/
7285
public $enablePkce = false;
7386

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

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

168190
/**
169191
* {@inheritdoc}
192+
* @throws InvalidConfigException
170193
*/
171194
public function applyAccessTokenToRequest($request, $accessToken)
172195
{
173-
$data = $request->getData();
174-
$data['access_token'] = $accessToken->getToken();
175-
$request->setData($data);
196+
switch($this->accessTokenLocation) {
197+
case self::ACCESS_TOKEN_LOCATION_BODY:
198+
$data = $request->getData();
199+
$data['access_token'] = $accessToken->getToken();
200+
$request->setData($data);
201+
break;
202+
case self::ACCESS_TOKEN_LOCATION_HEADER:
203+
$request->getHeaders()->set('Authorization', 'Bearer ' . $accessToken->getToken());
204+
break;
205+
default:
206+
throw new InvalidConfigException('Unknown access token location: ' . $this->accessTokenLocation);
207+
}
176208
}
177209

178210
/**

src/OpenIdConnect.php

+6-10
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77

88
namespace yii\authclient;
99

10-
use Jose\Component\Core\AlgorithmManager;
1110
use Jose\Component\Checker\AlgorithmChecker;
1211
use Jose\Component\Checker\HeaderCheckerManager;
12+
use Jose\Component\Core\AlgorithmManager;
1313
use Jose\Component\KeyManagement\JWKFactory;
1414
use Jose\Component\Signature\JWSLoader;
1515
use Jose\Component\Signature\JWSTokenSupport;
@@ -76,6 +76,11 @@
7676
*/
7777
class OpenIdConnect extends OAuth2
7878
{
79+
/**
80+
* {@inheritdoc}
81+
*/
82+
public $accessTokenLocation = OAuth2::ACCESS_TOKEN_LOCATION_HEADER;
83+
7984
/**
8085
* @var array Predefined OpenID Connect Claims
8186
* @see https://openid.net/specs/openid-connect-core-1_0.html#rfc.section.2
@@ -352,15 +357,6 @@ protected function initUserAttributes()
352357
return $idTokenData;
353358
}
354359

355-
/**
356-
* {@inheritdoc}
357-
*/
358-
public function applyAccessTokenToRequest($request, $accessToken)
359-
{
360-
// OpenID Connect requires bearer token auth for the user info endpoint
361-
$request->getHeaders()->set('Authorization', 'Bearer ' . $accessToken->getToken());
362-
}
363-
364360
/**
365361
* {@inheritdoc}
366362
*/

src/clients/GitHub.php

+5
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@
4040
*/
4141
class GitHub extends OAuth2
4242
{
43+
/**
44+
* {@inheritdoc}
45+
*/
46+
public $accessTokenLocation = OAuth2::ACCESS_TOKEN_LOCATION_HEADER;
47+
4348
/**
4449
* {@inheritdoc}
4550
*/

src/clients/Oauth2Client.php

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php
2+
/**
3+
* @link https://www.yiiframework.com/
4+
* @copyright Copyright (c) 2008 Yii Software LLC
5+
* @license https://www.yiiframework.com/license/
6+
*/
7+
8+
namespace yii\authclient\clients;
9+
10+
use yii\authclient\OAuth2;
11+
12+
/**
13+
* Generic client that allows authentication via OAuth 2.0.
14+
*
15+
* Example application configuration:
16+
*
17+
* ```php
18+
* 'components' => [
19+
* 'authClientCollection' => [
20+
* 'class' => 'yii\authclient\Collection',
21+
* 'clients' => [
22+
* 'oauth2' => [
23+
* 'class' => 'yii\authclient\clients\Oauth2Client',
24+
* 'authUrl' => 'https://oauth2service.com/oauth2/authorize',
25+
* 'tokenUrl' => 'https://oauth2service.com/oauth2/authorize',
26+
* 'apiBaseUrl' => 'https://oauth2service.com/api',
27+
* 'clientId' => 'your_app_client_id',
28+
* 'clientSecret' => 'your_app_client_secret',
29+
* 'name' => 'custom name',
30+
* 'title' => 'custom title'
31+
* ],
32+
* ],
33+
* ]
34+
* // ...
35+
* ]
36+
* ```
37+
*
38+
* @since 2.2.16
39+
*/
40+
class Oauth2Client extends OAuth2
41+
{
42+
43+
/**
44+
* {@inheritdoc}
45+
*/
46+
public $accessTokenLocation = self::ACCESS_TOKEN_LOCATION_HEADER;
47+
48+
/**
49+
* {@inheritdoc}
50+
*/
51+
protected function initUserAttributes()
52+
{
53+
return []; // Plain Oauth 2.0 doesn't specify user attributes.
54+
}
55+
}

src/clients/TwitterOAuth2.php

+6-9
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@
2727
*/
2828
class TwitterOAuth2 extends OAuth2
2929
{
30+
/**
31+
* {@inheritdoc}
32+
*/
33+
public $accessTokenLocation = OAuth2::ACCESS_TOKEN_LOCATION_HEADER;
34+
3035
/**
3136
* {@inheritdoc}
3237
*/
@@ -64,12 +69,4 @@ protected function defaultTitle()
6469
{
6570
return 'Twitter';
6671
}
67-
68-
/**
69-
* {@inheritdoc}
70-
*/
71-
public function applyAccessTokenToRequest($request, $accessToken)
72-
{
73-
$request->getHeaders()->set('Authorization', 'Bearer '. $accessToken->getToken());
74-
}
75-
}
72+
}

tests/clients/FacebookTest.php

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
namespace yiiunit\extensions\authclient\clients;
4+
5+
use yii\authclient\clients\Facebook;
6+
use yii\authclient\OAuth2;
7+
use yiiunit\extensions\authclient\clients\base\BaseOauth2ClientTestCase;
8+
9+
class FacebookTest extends BaseOauth2ClientTestCase
10+
{
11+
protected function createClient()
12+
{
13+
return new Facebook();
14+
}
15+
16+
protected function getExpectedTokenLocation()
17+
{
18+
return OAuth2::ACCESS_TOKEN_LOCATION_BODY;
19+
}
20+
}

tests/clients/GitHubTest.php

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
namespace yiiunit\extensions\authclient\clients;
4+
5+
use yii\authclient\clients\GitHub;
6+
use yii\authclient\OAuth2;
7+
use yiiunit\extensions\authclient\clients\base\BaseOauth2ClientTestCase;
8+
9+
class GitHubTest extends BaseOauth2ClientTestCase
10+
{
11+
protected function createClient()
12+
{
13+
return new GitHub();
14+
}
15+
16+
protected function getExpectedTokenLocation()
17+
{
18+
return OAuth2::ACCESS_TOKEN_LOCATION_HEADER;
19+
}
20+
21+
protected function getAccessTokenHeaderTypeName()
22+
{
23+
return 'token';
24+
}
25+
}

tests/clients/GoogleHybridTest.php

+8-2
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@
33
namespace yiiunit\extensions\authclient\clients;
44

55
use yii\authclient\clients\GoogleHybrid;
6-
use yiiunit\extensions\authclient\TestCase;
6+
use yii\authclient\OAuth2;
7+
use yiiunit\extensions\authclient\clients\base\BaseOauth2ClientTestCase;
78
use yiiunit\extensions\authclient\traits\OAuthDefaultReturnUrlTestTrait;
89

9-
class GoogleHybridTest extends TestCase
10+
class GoogleHybridTest extends BaseOauth2ClientTestCase
1011
{
1112
use OAuthDefaultReturnUrlTestTrait;
1213

@@ -15,6 +16,11 @@ protected function createClient()
1516
return new GoogleHybrid();
1617
}
1718

19+
protected function getExpectedTokenLocation()
20+
{
21+
return OAuth2::ACCESS_TOKEN_LOCATION_BODY;
22+
}
23+
1824
/**
1925
* Data provider for [[testDefaultReturnUrl]].
2026
* @return array test data.

tests/clients/GoogleTest.php

+10-17
Original file line numberDiff line numberDiff line change
@@ -3,29 +3,27 @@
33
namespace yiiunit\extensions\authclient\clients;
44

55
use yii\authclient\clients\Google;
6+
use yii\authclient\OAuth2;
67
use yii\authclient\OAuthToken;
78
use yii\authclient\signature\RsaSha;
8-
use yiiunit\extensions\authclient\TestCase;
9+
use yiiunit\extensions\authclient\clients\base\BaseOauth2ClientTestCase;
910
use yiiunit\extensions\authclient\traits\OAuthDefaultReturnUrlTestTrait;
1011

1112
/**
1213
* @group google
1314
*/
14-
class GoogleTest extends TestCase
15+
class GoogleTest extends BaseOauth2ClientTestCase
1516
{
1617
use OAuthDefaultReturnUrlTestTrait;
1718

18-
protected function setUp()
19+
protected function createClient()
1920
{
20-
$config = [
21-
'components' => [
22-
'request' => [
23-
'hostInfo' => 'http://testdomain.com',
24-
'scriptUrl' => '/index.php',
25-
],
26-
]
27-
];
28-
$this->mockApplication($config, '\yii\web\Application');
21+
return new Google();
22+
}
23+
24+
protected function getExpectedTokenLocation()
25+
{
26+
return OAuth2::ACCESS_TOKEN_LOCATION_BODY;
2927
}
3028

3129
public function testAuthenticateUserJwt()
@@ -45,11 +43,6 @@ public function testAuthenticateUserJwt()
4543
$this->assertNotEmpty($token->getToken());
4644
}
4745

48-
protected function createClient()
49-
{
50-
return new Google();
51-
}
52-
5346
/**
5447
* Data provider for [[testDefaultReturnUrl]].
5548
* @return array test data.

tests/clients/LinkedInTest.php

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
namespace yiiunit\extensions\authclient\clients;
4+
5+
use yii\authclient\clients\LinkedIn;
6+
use yii\authclient\OAuth2;
7+
use yiiunit\extensions\authclient\clients\base\BaseOauth2ClientTestCase;
8+
9+
class LinkedInTest extends BaseOauth2ClientTestCase
10+
{
11+
protected function createClient()
12+
{
13+
return new LinkedIn();
14+
}
15+
16+
protected function getExpectedTokenLocation()
17+
{
18+
return OAuth2::ACCESS_TOKEN_LOCATION_BODY;
19+
}
20+
21+
protected function getAccessTokenBodyParamName()
22+
{
23+
return 'oauth2_access_token';
24+
}
25+
}

tests/clients/LiveTest.php

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
namespace yiiunit\extensions\authclient\clients;
4+
5+
use yii\authclient\clients\Live;
6+
use yii\authclient\OAuth2;
7+
use yiiunit\extensions\authclient\clients\base\BaseOauth2ClientTestCase;
8+
9+
class LiveTest extends BaseOauth2ClientTestCase
10+
{
11+
protected function createClient()
12+
{
13+
return new Live();
14+
}
15+
16+
protected function getExpectedTokenLocation()
17+
{
18+
return OAuth2::ACCESS_TOKEN_LOCATION_BODY;
19+
}
20+
}

0 commit comments

Comments
 (0)