diff --git a/app/config/providers.php b/app/config/providers.php
index aa3877005c..1d364a3fcf 100644
--- a/app/config/providers.php
+++ b/app/config/providers.php
@@ -151,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/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/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 14e9aed6ed..ca2d3b2759 100644
--- a/public/scripts/views/forms/oauth-custom.js
+++ b/public/scripts/views/forms/oauth-custom.js
@@ -17,13 +17,18 @@
"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/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;
+ }
+}