diff --git a/app/config/providers.php b/app/config/providers.php index 27f63b88f..1d364a3fc 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/database/collection.phtml b/app/views/console/database/collection.phtml index 1bdef71d1..3651f0535 100644 --- a/app/views/console/database/collection.phtml +++ b/app/views/console/database/collection.phtml @@ -1040,7 +1040,7 @@ $logs = $this->getParam('logs', null);
- +
diff --git a/app/views/console/users/oauth/auth0.phtml b/app/views/console/users/oauth/auth0.phtml new file mode 100644 index 000000000..8509a582b --- /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/composer.lock b/composer.lock index 308452770..ca6633679 100644 --- a/composer.lock +++ b/composer.lock @@ -2250,16 +2250,16 @@ }, { "name": "utopia-php/framework", - "version": "0.19.9", + "version": "0.19.20", "source": { "type": "git", "url": "https://github.com/utopia-php/framework.git", - "reference": "4af9fc866edce1b8cff94731fb26c27599118e87" + "reference": "65ced168db8f6e188ceeb0d101f57552c3d8b2af" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/framework/zipball/4af9fc866edce1b8cff94731fb26c27599118e87", - "reference": "4af9fc866edce1b8cff94731fb26c27599118e87", + "url": "https://api.github.com/repos/utopia-php/framework/zipball/65ced168db8f6e188ceeb0d101f57552c3d8b2af", + "reference": "65ced168db8f6e188ceeb0d101f57552c3d8b2af", "shasum": "" }, "require": { @@ -2293,9 +2293,9 @@ ], "support": { "issues": "https://github.com/utopia-php/framework/issues", - "source": "https://github.com/utopia-php/framework/tree/0.19.9" + "source": "https://github.com/utopia-php/framework/tree/0.19.20" }, - "time": "2022-04-14T15:39:47+00:00" + "time": "2022-04-14T15:42:37+00:00" }, { "name": "utopia-php/image", diff --git a/docs/sdks/python/GETTING_STARTED.md b/docs/sdks/python/GETTING_STARTED.md index 4473088b3..46a3001ab 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 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 67fb21321..ca2d3b275 100644 --- a/public/scripts/views/forms/oauth-custom.js +++ b/public/scripts/views/forms/oauth-custom.js @@ -21,6 +21,10 @@ "clientSecret": "oauth2OktaClientSecret", "oktaDomain": "oauth2OktaDomain", "authorizationServerId": "oauth2OktaAuthorizationServerId" + }, + "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..b1c9c8ce1 --- /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