diff --git a/app/config/providers.php b/app/config/providers.php
index 9a6b5fb50..aa3877005 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',
diff --git a/app/views/console/users/oauth/auth0.phtml b/app/views/console/users/oauth/auth0.phtml
new file mode 100644
index 000000000..504eca6bc
--- /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/public/images/users/auth0.png b/public/images/users/auth0.png
new file mode 100644
index 000000000..d0800c629
Binary files /dev/null and b/public/images/users/auth0.png differ
diff --git a/public/scripts/views/forms/oauth-custom.js b/public/scripts/views/forms/oauth-custom.js
index 323c87441..22ab85f87 100644
--- a/public/scripts/views/forms/oauth-custom.js
+++ b/public/scripts/views/forms/oauth-custom.js
@@ -16,6 +16,10 @@
"keyId": "oauth2AppleKeyId",
"teamId": "oauth2AppleTeamId",
"p8": "oauth2AppleP8"
+ },
+ "Auth0": {
+ "clientSecret": "oauth2Auth0ClientSecret",
+ "auth0Domain": "oauth2Auth0Domain"
}
}
let provider = element.getAttribute("data-forms-oauth-custom");
diff --git a/src/Appwrite/Auth/OAuth2/Auth0.php b/src/Appwrite/Auth/OAuth2/Auth0.php
new file mode 100644
index 000000000..43a4038aa
--- /dev/null
+++ b/src/Appwrite/Auth/OAuth2/Auth0.php
@@ -0,0 +1,206 @@
+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)
+ {
+ 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->decodeJson();
+
+ return (isset($secret['clientSecret'])) ? $secret['clientSecret'] : '';
+ }
+
+ /**
+ * Extracts the Auth0 Domain from the JSON stored in appSecret. Defaults to 'common' as a fallback
+ * @return string
+ */
+ protected function getAuth0Domain(): string
+ {
+ $secret = $this->decodeJson();
+ return (isset($secret['auth0Domain'])) ? $secret['auth0Domain'] : '';
+ }
+
+ /**
+ * Decode the JSON stored in appSecret
+ * @return array
+ */
+ protected function decodeJson(): array
+ {
+ try {
+ $secret = \json_decode($this->appSecret, true);
+ } catch (\Throwable $th) {
+ throw new Exception('Invalid secret');
+ }
+ return $secret;
+ }
+}
\ No newline at end of file