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/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;
+ }
+}