Skip to content

Commit 2fa86c3

Browse files
authored
add support for custom scopes (#289)
- adds support for the `oauth_tokens` object in the authenticate API response - adds support for the new `provider_scopes` query parameter
1 parent a65be0b commit 2fa86c3

4 files changed

Lines changed: 132 additions & 4 deletions

File tree

lib/Resource/AuthenticationResponse.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
* @property string $accessToken
1111
* @property string $refreshToken
1212
* @property ?Impersonator $impersonator
13+
* @property ?OAuthTokens $oauthTokens
1314
*/
1415
class AuthenticationResponse extends BaseWorkOSResource
1516
{
@@ -19,12 +20,14 @@ class AuthenticationResponse extends BaseWorkOSResource
1920
"impersonator",
2021
"accessToken",
2122
"refreshToken",
23+
"oauthTokens",
2224
];
2325

2426
public const RESPONSE_TO_RESOURCE_KEY = [
2527
"organization_id" => "organizationId",
2628
"access_token" => "accessToken",
2729
"refresh_token" => "refreshToken",
30+
"oauth_tokens" => "oauthTokens",
2831
];
2932

3033
public static function constructFromResponse($response)
@@ -39,6 +42,10 @@ public static function constructFromResponse($response)
3942
);
4043
}
4144

45+
if (isset($response["oauth_tokens"])) {
46+
$instance->values["oauthTokens"] = OAuthTokens::constructFromResponse($response["oauth_tokens"]);
47+
}
48+
4249
return $instance;
4350
}
4451
}

lib/Resource/OAuthTokens.php

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
namespace WorkOS\Resource;
4+
5+
/**
6+
* Class OAuthTokens.
7+
*
8+
* @property string $accessToken
9+
* @property string $refreshToken
10+
* @property int $expiresAt
11+
* @property array $scopes
12+
*/
13+
class OAuthTokens extends BaseWorkOSResource
14+
{
15+
public const RESOURCE_ATTRIBUTES = [
16+
"accessToken",
17+
"refreshToken",
18+
"expiresAt",
19+
"scopes"
20+
];
21+
22+
public const RESPONSE_TO_RESOURCE_KEY = [
23+
"access_token" => "accessToken",
24+
"refresh_token" => "refreshToken",
25+
"expires_at" => "expiresAt",
26+
"scopes" => "scopes"
27+
];
28+
29+
public static function constructFromResponse($response)
30+
{
31+
$instance = parent::constructFromResponse($response);
32+
33+
// Ensure scopes is always an array
34+
if (!isset($instance->values["scopes"])) {
35+
$instance->values["scopes"] = [];
36+
}
37+
38+
return $instance;
39+
}
40+
}

lib/UserManagement.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -613,6 +613,7 @@ public function revokeInvitation($invitationId)
613613
* @param null|string $domainHint DDomain hint that will be passed as a parameter to the IdP login page
614614
* @param null|string $loginHint Username/email hint that will be passed as a parameter to the to IdP login page
615615
* @param null|string $screenHint The page that the user will be redirected to when the provider is authkit
616+
* @param null|array $providerScopes An array of provider-specific scopes
616617
*
617618
* @throws Exception\UnexpectedValueException
618619
* @throws Exception\ConfigurationException
@@ -627,7 +628,8 @@ public function getAuthorizationUrl(
627628
$organizationId = null,
628629
$domainHint = null,
629630
$loginHint = null,
630-
$screenHint = null
631+
$screenHint = null,
632+
$providerScopes = null
631633
) {
632634
$path = "user_management/authorize";
633635

@@ -689,6 +691,10 @@ public function getAuthorizationUrl(
689691
$params["screen_hint"] = $screenHint;
690692
}
691693

694+
if ($providerScopes && is_array($providerScopes)) {
695+
$params["provider_scopes"] = implode(",", $providerScopes);
696+
}
697+
692698
return Client::generateUrl($path, $params);
693699
}
694700

tests/WorkOS/UserManagementTest.php

Lines changed: 78 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,9 @@ public static function authorizationUrlTestDataProvider()
118118
["https://papagenos.com/auth/callback", null, null, "connection_123", null, null, "foo@workos.com"],
119119
["https://papagenos.com/auth/callback", null, null, "connection_123"],
120120
[null, null, null, "connection_123"],
121-
["https://papagenos.com/auth/callback", ["toppings" => "ham"], null, "connection_123"]
121+
["https://papagenos.com/auth/callback", ["toppings" => "ham"], null, "connection_123"],
122+
["https://papagenos.com/auth/callback", null, null, "connection_123", null, null, null, null, ["read", "write"]],
123+
[null, null, Resource\ConnectionType::GoogleOAuth, null, null, null, null, null, ["email", "profile"]]
122124
];
123125
}
124126

@@ -132,7 +134,9 @@ public function testAuthorizationURLExpectedParams(
132134
$connectionId,
133135
$organizationId = null,
134136
$domainHint = null,
135-
$loginHint = null
137+
$loginHint = null,
138+
$screenHint = null,
139+
$providerScopes = null
136140
) {
137141
$expectedParams = [
138142
"client_id" => WorkOS::getClientId(),
@@ -167,14 +171,20 @@ public function testAuthorizationURLExpectedParams(
167171
$expectedParams["login_hint"] = $loginHint;
168172
}
169173

174+
if ($providerScopes && is_array($providerScopes)) {
175+
$expectedParams["provider_scopes"] = implode(",", $providerScopes);
176+
}
177+
170178
$authorizationUrl = $this->userManagement->getAuthorizationUrl(
171179
$redirectUri,
172180
$state,
173181
$provider,
174182
$connectionId,
175183
$organizationId,
176184
$domainHint,
177-
$loginHint
185+
$loginHint,
186+
$screenHint,
187+
$providerScopes
178188
);
179189
$paramsString = \parse_url($authorizationUrl, \PHP_URL_QUERY);
180190
\parse_str($paramsString, $paramsArray);
@@ -347,6 +357,43 @@ public function testAuthenticateImpersonatorWithCode()
347357
], $response->impersonator->toArray());
348358
}
349359

360+
public function testAuthenticateWithOAuthTokensReturned()
361+
{
362+
$path = "user_management/authenticate";
363+
WorkOS::setApiKey("sk_test_12345");
364+
$result = $this->userAndOAuthTokensResponseFixture();
365+
366+
$params = [
367+
"client_id" => "project_0123456",
368+
"code" => "01E2RJ4C05B52KKZ8FSRDAP23J",
369+
"ip_address" => null,
370+
"user_agent" => null,
371+
"grant_type" => "authorization_code",
372+
"client_secret" => WorkOS::getApiKey()
373+
];
374+
375+
$this->mockRequest(
376+
Client::METHOD_POST,
377+
$path,
378+
null,
379+
$params,
380+
true,
381+
$result
382+
);
383+
384+
$userFixture = $this->userFixture();
385+
386+
$response = $this->userManagement->authenticateWithCode("project_0123456", "01E2RJ4C05B52KKZ8FSRDAP23J");
387+
$this->assertSame($userFixture, $response->user->toArray());
388+
389+
// Test OAuth tokens
390+
$this->assertNotNull($response->oauthTokens);
391+
$this->assertSame("oauth_access_token_123", $response->oauthTokens->accessToken);
392+
$this->assertSame("oauth_refresh_token_456", $response->oauthTokens->refreshToken);
393+
$this->assertSame(1640995200, $response->oauthTokens->expiresAt);
394+
$this->assertSame(["read", "write"], $response->oauthTokens->scopes);
395+
}
396+
350397
public function testEnrollAuthFactor()
351398
{
352399
$userId = "user_123456";
@@ -1491,6 +1538,34 @@ private function userAndImpersonatorResponseFixture()
14911538
]);
14921539
}
14931540

1541+
private function userAndOAuthTokensResponseFixture()
1542+
{
1543+
return json_encode([
1544+
"user" => [
1545+
"object" => "user",
1546+
"id" => "user_01H7X1M4TZJN5N4HG4XXMA1234",
1547+
"email" => "test@test.com",
1548+
"first_name" => "Damien",
1549+
"last_name" => "Alabaster",
1550+
"email_verified" => true,
1551+
"profile_picture_url" => "https://example.com/photo.jpg",
1552+
"last_sign_in_at" => "2021-06-25T19:07:33.155Z",
1553+
"created_at" => "2021-06-25T19:07:33.155Z",
1554+
"updated_at" => "2021-06-25T19:07:33.155Z",
1555+
"external_id" => null,
1556+
"metadata" => []
1557+
],
1558+
"access_token" => "01DMEK0J53CVMC32CK5SE0KZ8Q",
1559+
"refresh_token" => "refresh_token_123",
1560+
"oauth_tokens" => [
1561+
"access_token" => "oauth_access_token_123",
1562+
"refresh_token" => "oauth_refresh_token_456",
1563+
"expires_at" => 1640995200,
1564+
"scopes" => ["read", "write"]
1565+
]
1566+
]);
1567+
}
1568+
14941569
private function createUserAndTokenResponseFixture()
14951570
{
14961571
return json_encode([

0 commit comments

Comments
 (0)