diff --git a/app/config/providers.php b/app/config/providers.php index 9a6b5fb50f..1d364a3fcf 100644 --- a/app/config/providers.php +++ b/app/config/providers.php @@ -21,6 +21,16 @@ return [ // Ordered by ABC. 'beta' => true, 'mock' => false, ], + 'auth0' => [ + 'name' => 'Auth0', + 'developers' => 'https://auth0.com/developers', + 'icon' => 'icon-auth0', + 'enabled' => true, + 'sandbox' => false, + 'form' => 'auth0.phtml', + 'beta' => false, + 'mock' => false, + ], 'bitbucket' => [ 'name' => 'BitBucket', 'developers' => 'https://developer.atlassian.com/bitbucket', @@ -141,6 +151,16 @@ return [ // Ordered by ABC. 'beta' => false, 'mock' => false, ], + 'okta' => [ + 'name' => 'Okta', + 'developers' => 'https://developer.okta.com/', + 'icon' => 'icon-okta', + 'enabled' => true, + 'sandbox' => false, + 'form' => 'okta.phtml', + 'beta' => false, + 'mock' => false, + ], 'paypal' => [ 'name' => 'PayPal', 'developers' => 'https://developer.paypal.com/docs/api/overview/', diff --git a/app/controllers/api/avatars.php b/app/controllers/api/avatars.php index 9d483bf2b7..e3b56cf588 100644 --- a/app/controllers/api/avatars.php +++ b/app/controllers/api/avatars.php @@ -1,5 +1,7 @@ param('width', 400, new Range(0, 2000), 'Resize preview image width, Pass an integer between 0 to 2000.', true) ->param('height', 400, new Range(0, 2000), 'Resize preview image height, Pass an integer between 0 to 2000.', true) ->inject('response') - ->action(function ($url, $width, $height, $response) { - /** @var Appwrite\Utopia\Response $response */ + ->action(function ($url, $width, $height, Response $response) { $quality = 80; $output = 'png'; @@ -215,8 +214,7 @@ App::get('/v1/avatars/favicon') ->label('sdk.response.type', Response::CONTENT_TYPE_IMAGE) ->param('url', '', new URL(['http', 'https']), 'Website URL which you want to fetch the favicon from.') ->inject('response') - ->action(function ($url, $response) { - /** @var Appwrite\Utopia\Response $response */ + ->action(function ($url, Response $response) { $width = 56; $height = 56; @@ -371,8 +369,7 @@ App::get('/v1/avatars/qr') ->param('margin', 1, new Range(0, 10), 'Margin from edge. Pass an integer between 0 to 10. Defaults to 1.', true) ->param('download', false, new Boolean(true), 'Return resulting image with \'Content-Disposition: attachment \' headers for the browser to start downloading it. Pass 0 for no header, or 1 for otherwise. Default value is set to 0.', true) ->inject('response') - ->action(function ($text, $size, $margin, $download, $response) { - /** @var Appwrite\Utopia\Response $response */ + ->action(function ($text, $size, $margin, $download, Response $response) { $download = ($download === '1' || $download === 'true' || $download === 1 || $download === true); $options = new QROptions([ @@ -416,9 +413,7 @@ App::get('/v1/avatars/initials') ->param('background', '', new HexColor(), 'Changes background color. By default a random color will be picked and stay will persistent to the given name.', true) ->inject('response') ->inject('user') - ->action(function ($name, $width, $height, $color, $background, $response, $user) { - /** @var Appwrite\Utopia\Response $response */ - /** @var Utopia\Database\Document $user */ + ->action(function ($name, $width, $height, $color, $background, Response $response, Document $user) { $themes = [ ['color' => '#27005e', 'background' => '#e1d2f6'], // VIOLET diff --git a/app/controllers/api/database.php b/app/controllers/api/database.php index 1cf78b07e3..653097d12f 100644 --- a/app/controllers/api/database.php +++ b/app/controllers/api/database.php @@ -150,7 +150,7 @@ App::post('/v1/database/collections') ->label('sdk.response.model', Response::MODEL_COLLECTION) ->param('collectionId', '', new CustomId(), 'Unique Id. Choose your own unique ID or pass the string "unique()" to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Collection name. Max length: 128 chars.') - ->param('permission', null, new WhiteList(['document', 'collection']), 'Permissions type model to use for reading documents in this collection. You can use collection-level permission set once on the collection using the `read` and `write` params, or you can set document-level permission where each document read and write params will decide who has access to read and write to each document individually. [learn more about permissions](https://appwrite.io/docs/permissions) and get a full list of available permissions.') + ->param('permission', null, new WhiteList(['document', 'collection']), 'Specifies the permissions model used in this collection, which accepts either \'collection\' or \'document\'. For \'collection\' level permission, the permissions specified in read and write params are applied to all documents in the collection. For \'document\' level permissions, read and write permissions are specified in each document. [learn more about permissions](https://appwrite.io/docs/permissions) and get a full list of available permissions.') ->param('read', null, new Permissions(), 'An array of strings with read permissions. By default no user is granted with any read permissions. [learn more about permissions](https://appwrite.io/docs/permissions) and get a full list of available permissions.') ->param('write', null, new Permissions(), 'An array of strings with write permissions. By default no user is granted with any write permissions. [learn more about permissions](https://appwrite.io/docs/permissions) and get a full list of available permissions.') ->inject('response') diff --git a/app/controllers/api/health.php b/app/controllers/api/health.php index bc57aa8ccb..2ca66e24ba 100644 --- a/app/controllers/api/health.php +++ b/app/controllers/api/health.php @@ -1,13 +1,15 @@ desc('Get HTTP') @@ -21,8 +23,7 @@ App::get('/v1/health') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_HEALTH_STATUS) ->inject('response') - ->action(function ($response) { - /** @var Appwrite\Utopia\Response $response */ + ->action(function (Response $response) { $output = [ 'status' => 'pass', @@ -40,8 +41,7 @@ App::get('/v1/health/version') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_HEALTH_VERSION) ->inject('response') - ->action(function ($response) { - /** @var Appwrite\Utopia\Response $response */ + ->action(function (Response $response) { $response->dynamic(new Document([ 'version' => APP_VERSION_STABLE ]), Response::MODEL_HEALTH_VERSION); }); @@ -59,9 +59,7 @@ App::get('/v1/health/db') ->label('sdk.response.model', Response::MODEL_HEALTH_STATUS) ->inject('response') ->inject('utopia') - ->action(function ($response, $utopia) { - /** @var Appwrite\Utopia\Response $response */ - /** @var Utopia\App $utopia */ + ->action(function (Response $response, App $utopia) { $checkStart = \microtime(true); @@ -99,10 +97,7 @@ App::get('/v1/health/cache') ->label('sdk.response.model', Response::MODEL_HEALTH_STATUS) ->inject('response') ->inject('utopia') - ->action(function ($response, $utopia) { - /** @var Appwrite\Utopia\Response $response */ - /** @var Utopia\App $utopia */ - /** @var Redis */ + ->action(function (Response $response, App $utopia) { $checkStart = \microtime(true); @@ -132,8 +127,7 @@ App::get('/v1/health/time') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_HEALTH_TIME) ->inject('response') - ->action(function ($response) { - /** @var Appwrite\Utopia\Response $response */ + ->action(function (Response $response) { /* * Code from: @see https://www.beliefmedia.com.au/query-ntp-time-server @@ -190,8 +184,7 @@ App::get('/v1/health/queue/webhooks') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_HEALTH_QUEUE) ->inject('response') - ->action(function ($response) { - /** @var Appwrite\Utopia\Response $response */ + ->action(function (Response $response) { $response->dynamic(new Document([ 'size' => Resque::size(Event::WEBHOOK_QUEUE_NAME) ]), Response::MODEL_HEALTH_QUEUE); }, ['response']); @@ -208,8 +201,7 @@ App::get('/v1/health/queue/logs') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_HEALTH_QUEUE) ->inject('response') - ->action(function ($response) { - /** @var Appwrite\Utopia\Response $response */ + ->action(function (Response $response) { $response->dynamic(new Document([ 'size' => Resque::size(Event::AUDITS_QUEUE_NAME) ]), Response::MODEL_HEALTH_QUEUE); }, ['response']); @@ -226,8 +218,7 @@ App::get('/v1/health/queue/usage') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_HEALTH_QUEUE) ->inject('response') - ->action(function ($response) { - /** @var Appwrite\Utopia\Response $response */ + ->action(function (Response $response) { $response->dynamic(new Document([ 'size' => Resque::size(Event::USAGE_QUEUE_NAME) ]), Response::MODEL_HEALTH_QUEUE); }, ['response']); @@ -244,8 +235,7 @@ App::get('/v1/health/queue/certificates') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_HEALTH_QUEUE) ->inject('response') - ->action(function ($response) { - /** @var Appwrite\Utopia\Response $response */ + ->action(function (Response $response) { $response->dynamic(new Document([ 'size' => Resque::size(Event::CERTIFICATES_QUEUE_NAME) ]), Response::MODEL_HEALTH_QUEUE); }, ['response']); @@ -262,8 +252,7 @@ App::get('/v1/health/queue/functions') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_HEALTH_QUEUE) ->inject('response') - ->action(function ($response) { - /** @var Appwrite\Utopia\Response $response */ + ->action(function (Response $response) { $response->dynamic(new Document([ 'size' => Resque::size(Event::FUNCTIONS_QUEUE_NAME) ]), Response::MODEL_HEALTH_QUEUE); }, ['response']); @@ -280,8 +269,7 @@ App::get('/v1/health/storage/local') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_HEALTH_STATUS) ->inject('response') - ->action(function ($response) { - /** @var Appwrite\Utopia\Response $response */ + ->action(function (Response $response) { $checkStart = \microtime(true); @@ -322,8 +310,7 @@ App::get('/v1/health/anti-virus') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_HEALTH_ANTIVIRUS) ->inject('response') - ->action(function ($response) { - /** @var Appwrite\Utopia\Response $response */ + ->action(function (Response $response) { $output = [ 'status' => '', @@ -359,10 +346,7 @@ App::get('/v1/health/stats') // Currently only used internally ->inject('response') ->inject('register') ->inject('deviceFiles') - ->action(function ($response, $register, $deviceFiles) { - /** @var Appwrite\Utopia\Response $response */ - /** @var Utopia\Registry\Registry $register */ - /** @var Utopia\Storage\Device $deviceFiles */ + ->action(function (Response $response, Registry $register, Device $deviceFiles) { $cache = $register->get('cache'); diff --git a/app/controllers/api/locale.php b/app/controllers/api/locale.php index 34018f6e90..bd3891a893 100644 --- a/app/controllers/api/locale.php +++ b/app/controllers/api/locale.php @@ -1,9 +1,12 @@ desc('Get User Locale') @@ -20,12 +23,8 @@ App::get('/v1/locale') ->inject('response') ->inject('locale') ->inject('geodb') - ->action(function ($request, $response, $locale, $geodb) { - /** @var Appwrite\Utopia\Request $request */ - /** @var Appwrite\Utopia\Response $response */ - /** @var Utopia\Locale\Locale $locale */ - /** @var MaxMind\Db\Reader $geodb */ - + ->action(function (Request $request, Response $response, Locale $locale, Reader $geodb) { + $eu = Config::getParam('locale-eu'); $currencies = Config::getParam('locale-currencies'); $output = []; @@ -82,10 +81,8 @@ App::get('/v1/locale/countries') ->label('sdk.response.model', Response::MODEL_COUNTRY_LIST) ->inject('response') ->inject('locale') - ->action(function ($response, $locale) { - /** @var Appwrite\Utopia\Response $response */ - /** @var Utopia\Locale\Locale $locale */ - + ->action(function (Response $response, Locale $locale) { + $list = Config::getParam('locale-countries'); /* @var $list array */ $output = []; @@ -116,9 +113,7 @@ App::get('/v1/locale/countries/eu') ->label('sdk.response.model', Response::MODEL_COUNTRY_LIST) ->inject('response') ->inject('locale') - ->action(function ($response, $locale) { - /** @var Appwrite\Utopia\Response $response */ - /** @var Utopia\Locale\Locale $locale */ + ->action(function (Response $response, Locale $locale) { $eu = Config::getParam('locale-eu'); $output = []; @@ -152,10 +147,8 @@ App::get('/v1/locale/countries/phones') ->label('sdk.response.model', Response::MODEL_PHONE_LIST) ->inject('response') ->inject('locale') - ->action(function ($response, $locale) { - /** @var Appwrite\Utopia\Response $response */ - /** @var Utopia\Locale\Locale $locale */ - + ->action(function (Response $response, Locale $locale) { + $list = Config::getParam('locale-phones'); /* @var $list array */ $output = []; @@ -187,9 +180,7 @@ App::get('/v1/locale/continents') ->label('sdk.response.model', Response::MODEL_CONTINENT_LIST) ->inject('response') ->inject('locale') - ->action(function ($response, $locale) { - /** @var Appwrite\Utopia\Response $response */ - /** @var Utopia\Locale\Locale $locale */ + ->action(function (Response $response, Locale $locale) { $list = Config::getParam('locale-continents'); /* @var $list array */ @@ -219,8 +210,7 @@ App::get('/v1/locale/currencies') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_CURRENCY_LIST) ->inject('response') - ->action(function ($response) { - /** @var Appwrite\Utopia\Response $response */ + ->action(function (Response $response) { $list = Config::getParam('locale-currencies'); @@ -242,8 +232,7 @@ App::get('/v1/locale/languages') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_LANGUAGE_LIST) ->inject('response') - ->action(function ($response) { - /** @var Appwrite\Utopia\Response $response */ + ->action(function (Response $response) { $list = Config::getParam('locale-languages'); diff --git a/app/views/console/users/oauth/auth0.phtml b/app/views/console/users/oauth/auth0.phtml new file mode 100644 index 0000000000..8509a582b5 --- /dev/null +++ b/app/views/console/users/oauth/auth0.phtml @@ -0,0 +1,12 @@ +getParam('provider', ''); +?> + + + + + + + + + \ No newline at end of file diff --git a/app/views/console/users/oauth/okta.phtml b/app/views/console/users/oauth/okta.phtml new file mode 100644 index 0000000000..2459e1543c --- /dev/null +++ b/app/views/console/users/oauth/okta.phtml @@ -0,0 +1,14 @@ +getParam('provider', ''); +?> + + + + + + + + + + + \ No newline at end of file diff --git a/docs/sdks/python/GETTING_STARTED.md b/docs/sdks/python/GETTING_STARTED.md index 4473088b36..46a3001ab9 100644 --- a/docs/sdks/python/GETTING_STARTED.md +++ b/docs/sdks/python/GETTING_STARTED.md @@ -1,7 +1,7 @@ ## Getting Started ### Init your SDK -Initialize your SDK with your Appwrite server API endpoint and project ID which can be found in your project settings page and your new API secret Key from project's API keys section. +Initialize your SDK with your Appwrite server API endpoint and project ID which can be found on your project settings page and your new API secret Key from project's API keys section. ```python from appwrite.client import Client diff --git a/public/images/users/auth0.png b/public/images/users/auth0.png new file mode 100644 index 0000000000..d0800c6294 Binary files /dev/null and b/public/images/users/auth0.png differ diff --git a/public/images/users/okta.png b/public/images/users/okta.png new file mode 100644 index 0000000000..bdf7907f46 Binary files /dev/null and b/public/images/users/okta.png differ diff --git a/public/scripts/views/forms/oauth-custom.js b/public/scripts/views/forms/oauth-custom.js index fd8bd855d0..ca2d3b2759 100644 --- a/public/scripts/views/forms/oauth-custom.js +++ b/public/scripts/views/forms/oauth-custom.js @@ -16,10 +16,19 @@ "keyID": "oauth2AppleKeyId", "teamID": "oauth2AppleTeamId", "p8": "oauth2AppleP8" + }, + "Okta": { + "clientSecret": "oauth2OktaClientSecret", + "oktaDomain": "oauth2OktaDomain", + "authorizationServerId": "oauth2OktaAuthorizationServerId" + }, + "Auth0": { + "clientSecret": "oauth2Auth0ClientSecret", + "auth0Domain": "oauth2Auth0Domain" } } let provider = element.getAttribute("data-forms-oauth-custom"); - if (!provider || !providers.hasOwnProperty(provider)) { console.error("Provider for custom form not set or unkown") } + if (!provider || !providers.hasOwnProperty(provider)) { console.error("Provider for custom form not set or unknown") } let config = providers[provider]; // Add Change Listeners for element diff --git a/src/Appwrite/Auth/OAuth2/Auth0.php b/src/Appwrite/Auth/OAuth2/Auth0.php new file mode 100644 index 0000000000..b1c9c8ce1f --- /dev/null +++ b/src/Appwrite/Auth/OAuth2/Auth0.php @@ -0,0 +1,210 @@ +getAuth0Domain().'/authorize?'.\http_build_query([ + 'client_id' => $this->appID, + 'redirect_uri' => $this->callback, + 'state'=> \json_encode($this->state), + 'scope'=> \implode(' ', $this->getScopes()), + 'response_type' => 'code' + ]); + } + + /** + * @param string $code + * + * @return array + */ + protected function getTokens(string $code): array + { + if(empty($this->tokens)) { + $headers = ['Content-Type: application/x-www-form-urlencoded']; + $this->tokens = \json_decode($this->request( + 'POST', + 'https://'.$this->getAuth0Domain().'/oauth/token', + $headers, + \http_build_query([ + 'code' => $code, + 'client_id' => $this->appID, + 'client_secret' => $this->getClientSecret(), + 'redirect_uri' => $this->callback, + 'scope' => \implode(' ', $this->getScopes()), + 'grant_type' => 'authorization_code' + ]) + ), true); + } + + return $this->tokens; + } + + + /** + * @param string $refreshToken + * + * @return array + */ + public function refreshTokens(string $refreshToken): array + { + $headers = ['Content-Type: application/x-www-form-urlencoded']; + $this->tokens = \json_decode($this->request( + 'POST', + 'https://'.$this->getAuth0Domain().'/oauth/token', + $headers, + \http_build_query([ + 'refresh_token' => $refreshToken, + 'client_id' => $this->appID, + 'client_secret' => $this->getClientSecret(), + 'grant_type' => 'refresh_token' + ]) + ), true); + + if(empty($this->tokens['refresh_token'])) { + $this->tokens['refresh_token'] = $refreshToken; + } + + return $this->tokens; + } + + /** + * @param string $accessToken + * + * @return string + */ + public function getUserID(string $accessToken): string + { + $user = $this->getUser($accessToken); + + if (isset($user['sub'])) { + return $user['sub']; + } + + return ''; + } + + /** + * @param string $accessToken + * + * @return string + */ + public function getUserEmail(string $accessToken): string + { + $user = $this->getUser($accessToken); + + if (isset($user['email'])) { + return $user['email']; + } + + return ''; + } + + /** + * @param string $accessToken + * + * @return string + */ + public function getUserName(string $accessToken): string + { + $user = $this->getUser($accessToken); + + if (isset($user['name'])) { + return $user['name']; + } + + return ''; + } + + /** + * @param string $accessToken + * + * @return array + */ + protected function getUser(string $accessToken): array + { + if (empty($this->user)) { + $headers = ['Authorization: Bearer '. \urlencode($accessToken)]; + $user = $this->request('GET', 'https://'.$this->getAuth0Domain().'/userinfo', $headers); + $this->user = \json_decode($user, true); + } + + return $this->user; + } + + /** + * Extracts the Client Secret from the JSON stored in appSecret + * + * @return string + */ + protected function getClientSecret(): string + { + $secret = $this->getAppSecret(); + + return (isset($secret['clientSecret'])) ? $secret['clientSecret'] : ''; + } + + /** + * Extracts the Auth0 Domain from the JSON stored in appSecret + * + * @return string + */ + protected function getAuth0Domain(): string + { + $secret = $this->getAppSecret(); + return (isset($secret['auth0Domain'])) ? $secret['auth0Domain'] : ''; + } + + /** + * Decode the JSON stored in appSecret + * + * @return array + */ + protected function getAppSecret(): array + { + try { + $secret = \json_decode($this->appSecret, true, 512, JSON_THROW_ON_ERROR); + } catch (\Throwable $th) { + throw new \Exception('Invalid secret'); + } + return $secret; + } +} \ No newline at end of file diff --git a/src/Appwrite/Auth/OAuth2/Okta.php b/src/Appwrite/Auth/OAuth2/Okta.php new file mode 100644 index 0000000000..7b1b0d19e1 --- /dev/null +++ b/src/Appwrite/Auth/OAuth2/Okta.php @@ -0,0 +1,221 @@ +getOktaDomain().'/oauth2/'.$this->getAuthorizationServerId().'/v1/authorize?'.\http_build_query([ + 'client_id' => $this->appID, + 'redirect_uri' => $this->callback, + 'state'=> \json_encode($this->state), + 'scope'=> \implode(' ', $this->getScopes()), + 'response_type' => 'code' + ]); + } + + /** + * @param string $code + * + * @return array + */ + protected function getTokens(string $code): array + { + if(empty($this->tokens)) { + $headers = ['Content-Type: application/x-www-form-urlencoded']; + $this->tokens = \json_decode($this->request( + 'POST', + 'https://'.$this->getOktaDomain().'/oauth2/'.$this->getAuthorizationServerId().'/v1/token', + $headers, + \http_build_query([ + 'code' => $code, + 'client_id' => $this->appID, + 'client_secret' => $this->getClientSecret(), + 'redirect_uri' => $this->callback, + 'scope' => \implode(' ', $this->getScopes()), + 'grant_type' => 'authorization_code' + ]) + ), true); + } + + return $this->tokens; + } + + + /** + * @param string $refreshToken + * + * @return array + */ + public function refreshTokens(string $refreshToken): array + { + $headers = ['Content-Type: application/x-www-form-urlencoded']; + $this->tokens = \json_decode($this->request( + 'POST', + 'https://'.$this->getOktaDomain().'/oauth2/'.$this->getAuthorizationServerId().'/v1/token', + $headers, + \http_build_query([ + 'refresh_token' => $refreshToken, + 'client_id' => $this->appID, + 'client_secret' => $this->getClientSecret(), + 'grant_type' => 'refresh_token' + ]) + ), true); + + if(empty($this->tokens['refresh_token'])) { + $this->tokens['refresh_token'] = $refreshToken; + } + + return $this->tokens; + } + + /** + * @param string $accessToken + * + * @return string + */ + public function getUserID(string $accessToken): string + { + $user = $this->getUser($accessToken); + + if (isset($user['sub'])) { + return $user['sub']; + } + + return ''; + } + + /** + * @param string $accessToken + * + * @return string + */ + public function getUserEmail(string $accessToken): string + { + $user = $this->getUser($accessToken); + + if (isset($user['email'])) { + return $user['email']; + } + + return ''; + } + + /** + * @param string $accessToken + * + * @return string + */ + public function getUserName(string $accessToken): string + { + $user = $this->getUser($accessToken); + + if (isset($user['name'])) { + return $user['name']; + } + + return ''; + } + + /** + * @param string $accessToken + * + * @return array + */ + protected function getUser(string $accessToken): array + { + if (empty($this->user)) { + $headers = ['Authorization: Bearer '. \urlencode($accessToken)]; + $user = $this->request('GET', 'https://'.$this->getOktaDomain().'/oauth2/'.$this->getAuthorizationServerId().'/v1/userinfo', $headers); + $this->user = \json_decode($user, true); + } + + return $this->user; + } + + /** + * Extracts the Client Secret from the JSON stored in appSecret + * + * @return string + */ + protected function getClientSecret(): string + { + $secret = $this->getAppSecret(); + + return (isset($secret['clientSecret'])) ? $secret['clientSecret'] : ''; + } + + /** + * Extracts the Okta Domain from the JSON stored in appSecret + * + * @return string + */ + protected function getOktaDomain(): string + { + $secret = $this->getAppSecret(); + return (isset($secret['oktaDomain'])) ? $secret['oktaDomain'] : ''; + } + + /** + * Extracts the Okta Authorization Server ID from the JSON stored in appSecret + * + * @return string + */ + protected function getAuthorizationServerId(): string + { + $secret = $this->getAppSecret(); + return (isset($secret['authorizationServerId'])) ? $secret['authorizationServerId'] : 'default'; + } + + /** + * Decode the JSON stored in appSecret + * + * @return array + */ + protected function getAppSecret(): array + { + try { + $secret = \json_decode($this->appSecret, true, 512, JSON_THROW_ON_ERROR); + } catch (\Throwable $th) { + throw new \Exception('Invalid secret'); + } + return $secret; + } +}