|
5 | 5 | use Saloon\Helpers\Str; |
6 | 6 | use Saloon\Helpers\Date; |
7 | 7 | use Saloon\Http\Response; |
| 8 | +use Saloon\Contracts\Request; |
8 | 9 | use Saloon\Http\Faking\MockClient; |
9 | 10 | use Saloon\Http\Faking\MockResponse; |
| 11 | +use Saloon\Http\OAuth2\GetUserRequest; |
10 | 12 | use Saloon\Exceptions\InvalidStateException; |
| 13 | +use Saloon\Http\OAuth2\GetAccessTokenRequest; |
11 | 14 | use Saloon\Http\Auth\AccessTokenAuthenticator; |
| 15 | +use Saloon\Http\OAuth2\GetRefreshTokenRequest; |
12 | 16 | use Saloon\Tests\Fixtures\Connectors\OAuth2Connector; |
13 | 17 | use Saloon\Tests\Fixtures\Authenticators\CustomOAuthAuthenticator; |
14 | 18 | use Saloon\Tests\Fixtures\Connectors\CustomResponseOAuth2Connector; |
|
73 | 77 | expect($authenticator->getExpiresAt())->toBeInstanceOf(DateTimeImmutable::class); |
74 | 78 | }); |
75 | 79 |
|
| 80 | +test('you can tap into the access token request and modify it', function () { |
| 81 | + $mockClient = new MockClient([ |
| 82 | + MockResponse::make(['access_token' => 'access', 'refresh_token' => 'refresh', 'expires_in' => 3600], 200), |
| 83 | + ]); |
| 84 | + |
| 85 | + $connector = new OAuth2Connector; |
| 86 | + |
| 87 | + $connector->withMockClient($mockClient); |
| 88 | + |
| 89 | + $authenticator = $connector->getAccessToken('code', requestModifier: function (Request $request) { |
| 90 | + $request->query()->add('yee', 'haw'); |
| 91 | + }); |
| 92 | + |
| 93 | + expect($authenticator)->toBeInstanceOf(AccessTokenAuthenticator::class); |
| 94 | + expect($authenticator->getAccessToken())->toEqual('access'); |
| 95 | + expect($authenticator->getRefreshToken())->toEqual('refresh'); |
| 96 | + expect($authenticator->getExpiresAt())->toBeInstanceOf(DateTimeImmutable::class); |
| 97 | + |
| 98 | + $mockClient->assertSentCount(1); |
| 99 | + |
| 100 | + expect($mockClient->getLastPendingRequest()->query()->all())->toEqual(['yee' => 'haw']); |
| 101 | +}); |
| 102 | + |
76 | 103 | test('you can request the original response instead of the authenticator on the create tokens method', function () { |
77 | 104 | $mockClient = new MockClient([ |
78 | 105 | MockResponse::make(['access_token' => 'access', 'refresh_token' => 'refresh', 'expires_in' => 3600]), |
|
116 | 143 | expect($newAuthenticator->getExpiresAt())->toBeInstanceOf(DateTimeImmutable::class); |
117 | 144 | }); |
118 | 145 |
|
| 146 | +test('you can tap into the refresh token request', function () { |
| 147 | + $mockClient = new MockClient([ |
| 148 | + MockResponse::make(['access_token' => 'access-new', 'refresh_token' => 'refresh-new', 'expires_in' => 3600]), |
| 149 | + ]); |
| 150 | + |
| 151 | + $connector = new OAuth2Connector; |
| 152 | + |
| 153 | + $connector->withMockClient($mockClient); |
| 154 | + |
| 155 | + $authenticator = new AccessTokenAuthenticator('access', 'refresh', Date::now()->addSeconds(3600)->toDateTime()); |
| 156 | + |
| 157 | + $newAuthenticator = $connector->refreshAccessToken($authenticator, requestModifier: function (Request $request) { |
| 158 | + $request->query()->add('yee', 'haw'); |
| 159 | + }); |
| 160 | + |
| 161 | + expect($newAuthenticator)->toBeInstanceOf(AccessTokenAuthenticator::class); |
| 162 | + expect($newAuthenticator->getAccessToken())->toEqual('access-new'); |
| 163 | + expect($newAuthenticator->getRefreshToken())->toEqual('refresh-new'); |
| 164 | + expect($newAuthenticator->getExpiresAt())->toBeInstanceOf(DateTimeImmutable::class); |
| 165 | + |
| 166 | + $mockClient->assertSentCount(1); |
| 167 | + |
| 168 | + expect($mockClient->getLastPendingRequest()->query()->all())->toEqual(['yee' => 'haw']); |
| 169 | +}); |
| 170 | + |
119 | 171 | test('the refreshAccessToken method throws an exception if you provide it an authenticator that is not refreshable', function () { |
120 | 172 | $mockClient = new MockClient([ |
121 | 173 | MockResponse::make(['access_token' => 'access-new', 'refresh_token' => 'refresh-new', 'expires_in' => 3600]), |
|
173 | 225 | ]); |
174 | 226 | }); |
175 | 227 |
|
| 228 | +test('you can tap into the the user request', function () { |
| 229 | + $mockClient = new MockClient([ |
| 230 | + MockResponse::make(['user' => 'Sam']), |
| 231 | + ]); |
| 232 | + |
| 233 | + $connector = new OAuth2Connector; |
| 234 | + $connector->withMockClient($mockClient); |
| 235 | + |
| 236 | + $accessToken = new AccessTokenAuthenticator('access', 'refresh', Date::now()->addSeconds(3600)->toDateTime()); |
| 237 | + |
| 238 | + $response = $connector->getUser($accessToken, function (Request $request) { |
| 239 | + $request->query()->add('yee', 'haw'); |
| 240 | + }); |
| 241 | + |
| 242 | + expect($response)->toBeInstanceOf(Response::class); |
| 243 | + |
| 244 | + $pendingRequest = $response->getPendingRequest(); |
| 245 | + |
| 246 | + expect($pendingRequest->query()->all())->toEqual(['yee' => 'haw']); |
| 247 | + |
| 248 | + expect($pendingRequest->headers()->all())->toEqual([ |
| 249 | + 'Accept' => 'application/json', |
| 250 | + 'Authorization' => 'Bearer access', |
| 251 | + 'Content-Type' => 'application/x-www-form-urlencoded', |
| 252 | + ]); |
| 253 | +}); |
| 254 | + |
176 | 255 | test('you can customize the oauth authenticator', function () { |
177 | 256 | $mockClient = new MockClient([ |
178 | 257 | MockResponse::make(['access_token' => 'access-new', 'refresh_token' => 'refresh-new', 'expires_in' => 3600]), |
|
186 | 265 | expect($authenticator)->toBeInstanceOf(CustomOAuthAuthenticator::class); |
187 | 266 | expect($authenticator->getGreeting())->toEqual('Howdy!'); |
188 | 267 | }); |
| 268 | + |
| 269 | +test('you can register a global request modifier that is called on every step of the OAuth2 process', function () { |
| 270 | + $mockClient = new MockClient([ |
| 271 | + GetAccessTokenRequest::class => MockResponse::make(['access_token' => 'access', 'refresh_token' => 'refresh', 'expires_in' => 3600], 200), |
| 272 | + GetRefreshTokenRequest::class => MockResponse::make(['access_token' => 'access-new', 'refresh_token' => 'refresh-new', 'expires_in' => 3600]), |
| 273 | + GetUserRequest::class => MockResponse::make(['user' => 'Sam']), |
| 274 | + ]); |
| 275 | + |
| 276 | + $connector = new OAuth2Connector; |
| 277 | + $requests = []; |
| 278 | + |
| 279 | + $connector->oauthConfig()->setRequestModifier(function (Request $request) use (&$requests) { |
| 280 | + $requests[] = $request::class; |
| 281 | + |
| 282 | + match ($request::class) { |
| 283 | + GetAccessTokenRequest::class => $request->query()->add('request', 'access'), |
| 284 | + GetRefreshTokenRequest::class => $request->query()->add('request', 'refresh'), |
| 285 | + GetUserRequest::class => $request->query()->add('request', 'user'), |
| 286 | + }; |
| 287 | + }); |
| 288 | + |
| 289 | + $connector->withMockClient($mockClient); |
| 290 | + |
| 291 | + $authenticator = $connector->getAccessToken('code'); |
| 292 | + |
| 293 | + expect($authenticator)->toBeInstanceOf(AccessTokenAuthenticator::class); |
| 294 | + expect($authenticator->getAccessToken())->toEqual('access'); |
| 295 | + expect($authenticator->getRefreshToken())->toEqual('refresh'); |
| 296 | + expect($authenticator->getExpiresAt())->toBeInstanceOf(DateTimeImmutable::class); |
| 297 | + expect($mockClient->getLastPendingRequest()->query()->all())->toEqual(['request' => 'access']); |
| 298 | + |
| 299 | + $newAuthenticator = $connector->refreshAccessToken($authenticator); |
| 300 | + |
| 301 | + expect($newAuthenticator)->toBeInstanceOf(AccessTokenAuthenticator::class); |
| 302 | + expect($newAuthenticator->getAccessToken())->toEqual('access-new'); |
| 303 | + expect($newAuthenticator->getRefreshToken())->toEqual('refresh-new'); |
| 304 | + expect($newAuthenticator->getExpiresAt())->toBeInstanceOf(DateTimeImmutable::class); |
| 305 | + expect($mockClient->getLastPendingRequest()->query()->all())->toEqual(['request' => 'refresh']); |
| 306 | + |
| 307 | + $response = $connector->getUser($newAuthenticator); |
| 308 | + |
| 309 | + expect($response)->toBeInstanceOf(Response::class); |
| 310 | + expect($mockClient->getLastPendingRequest()->query()->all())->toEqual(['request' => 'user']); |
| 311 | + |
| 312 | + $pendingRequest = $response->getPendingRequest(); |
| 313 | + |
| 314 | + expect($pendingRequest->headers()->all())->toEqual([ |
| 315 | + 'Accept' => 'application/json', |
| 316 | + 'Authorization' => 'Bearer access-new', |
| 317 | + 'Content-Type' => 'application/x-www-form-urlencoded', |
| 318 | + ]); |
| 319 | + |
| 320 | + expect($requests)->toEqual([ |
| 321 | + GetAccessTokenRequest::class, |
| 322 | + GetRefreshTokenRequest::class, |
| 323 | + GetUserRequest::class, |
| 324 | + ]); |
| 325 | +}); |
0 commit comments