mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
Merge pull request #11993 from appwrite/feat-public-oauth2-endpoints
Feat: Public project OAuth2 configuration API
This commit is contained in:
@@ -146,3 +146,5 @@ _APP_STATS_USAGE_DUAL_WRITING_DBS=database_db_main
|
||||
_APP_TRUSTED_HEADERS=x-forwarded-for
|
||||
_APP_POOL_ADAPTER=stack
|
||||
_APP_WORKER_SCREENSHOTS_ROUTER=http://appwrite
|
||||
_TESTS_OAUTH2_GITHUB_CLIENT_ID=
|
||||
_TESTS_OAUTH2_GITHUB_CLIENT_SECRET=
|
||||
|
||||
@@ -456,8 +456,10 @@ jobs:
|
||||
name: ${{ env.IMAGE }}
|
||||
path: /tmp
|
||||
|
||||
- name: Set database environment
|
||||
- name: Set environment
|
||||
run: |
|
||||
echo "_APP_OPTIONS_ROUTER_PROTECTION=enabled" >> $GITHUB_ENV
|
||||
|
||||
if [ "${{ matrix.database }}" = "MariaDB" ]; then
|
||||
echo "COMPOSE_PROFILES=mariadb" >> $GITHUB_ENV
|
||||
echo "_APP_DB_ADAPTER=mariadb" >> $GITHUB_ENV
|
||||
@@ -526,6 +528,8 @@ jobs:
|
||||
|
||||
docker compose exec -T \
|
||||
-e _APP_E2E_RESPONSE_FORMAT="${{ github.event.inputs.response_format }}" \
|
||||
-e _TESTS_OAUTH2_GITHUB_CLIENT_ID="${{ secrets.TESTS_OAUTH2_GITHUB_CLIENT_ID }}" \
|
||||
-e _TESTS_OAUTH2_GITHUB_CLIENT_SECRET="${{ secrets.TESTS_OAUTH2_GITHUB_CLIENT_SECRET }}" \
|
||||
appwrite vendor/bin/paratest --processes "$PARATEST_PROCESSES" $FUNCTIONAL_FLAG "$SERVICE_PATH" --exclude-group abuseEnabled --exclude-group screenshots --log-junit tests/e2e/Services/${{ matrix.service }}/junit.xml
|
||||
|
||||
- name: Failure Logs
|
||||
|
||||
@@ -167,6 +167,17 @@ return [
|
||||
'mock' => false,
|
||||
'class' => 'Appwrite\\Auth\\OAuth2\\Figma',
|
||||
],
|
||||
'fusionauth' => [
|
||||
'name' => 'FusionAuth',
|
||||
'developers' => 'https://fusionauth.io/docs/',
|
||||
'icon' => 'icon-fusionauth',
|
||||
'enabled' => true,
|
||||
'sandbox' => false,
|
||||
'form' => 'fusionauth.phtml',
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
'class' => 'Appwrite\\Auth\\OAuth2\\FusionAuth',
|
||||
],
|
||||
'github' => [
|
||||
'name' => 'GitHub',
|
||||
'developers' => 'https://developer.github.com/',
|
||||
@@ -200,6 +211,28 @@ return [
|
||||
'mock' => false,
|
||||
'class' => 'Appwrite\\Auth\\OAuth2\\Google',
|
||||
],
|
||||
'keycloak' => [
|
||||
'name' => 'Keycloak',
|
||||
'developers' => 'https://www.keycloak.org/documentation',
|
||||
'icon' => 'icon-keycloak',
|
||||
'enabled' => true,
|
||||
'sandbox' => false,
|
||||
'form' => 'keycloak.phtml',
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
'class' => 'Appwrite\\Auth\\OAuth2\\Keycloak',
|
||||
],
|
||||
'kick' => [
|
||||
'name' => 'Kick',
|
||||
'developers' => 'https://docs.kick.com/',
|
||||
'icon' => 'icon-kick',
|
||||
'enabled' => true,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
'class' => 'Appwrite\\Auth\\OAuth2\\Kick',
|
||||
],
|
||||
'linkedin' => [
|
||||
'name' => 'LinkedIn',
|
||||
'developers' => 'https://developer.linkedin.com/',
|
||||
|
||||
@@ -55,6 +55,8 @@ $admins = [
|
||||
'tables.write',
|
||||
'platforms.read',
|
||||
'platforms.write',
|
||||
'oauth2.read',
|
||||
'oauth2.write',
|
||||
'mocks.read',
|
||||
'mocks.write',
|
||||
'policies.read',
|
||||
|
||||
@@ -228,4 +228,12 @@ return [ // List of publicly visible scopes
|
||||
"description" =>
|
||||
"Access to create, update, and delete project\'s templates",
|
||||
],
|
||||
"oauth2.read" => [
|
||||
"description" =>
|
||||
"Access to read project\'s OAuth2 configuration",
|
||||
],
|
||||
"oauth2.write" => [
|
||||
"description" =>
|
||||
"Access to update project\'s OAuth2 configuration",
|
||||
],
|
||||
];
|
||||
|
||||
@@ -58,23 +58,11 @@ Http::get('/v1/projects/:projectId')
|
||||
$response->dynamic($project, Response::MODEL_PROJECT);
|
||||
});
|
||||
|
||||
// Backwards compatibility
|
||||
Http::patch('/v1/projects/:projectId/oauth2')
|
||||
->desc('Update project OAuth2')
|
||||
->groups(['api', 'projects'])
|
||||
->label('scope', 'projects.write')
|
||||
->label('sdk', new Method(
|
||||
namespace: 'projects',
|
||||
group: 'auth',
|
||||
name: 'updateOAuth2',
|
||||
description: '/docs/references/projects/update-oauth2.md',
|
||||
auth: [AuthType::ADMIN],
|
||||
responses: [
|
||||
new SDKResponse(
|
||||
code: Response::STATUS_CODE_OK,
|
||||
model: Response::MODEL_PROJECT,
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('projectId', '', fn (Database $dbForPlatform) => new UID($dbForPlatform->getAdapter()->getMaxUIDLength()), 'Project unique ID.', false, ['dbForPlatform'])
|
||||
->param('provider', '', new WhiteList(\array_keys(Config::getParam('oAuthProviders')), true), 'Provider Name')
|
||||
->param('appId', null, new Nullable(new Text(256)), 'Provider app ID. Max length: 256 chars.', true)
|
||||
|
||||
@@ -120,7 +120,7 @@ function router(Http $utopia, Database $dbForPlatform, callable $getProjectDB, S
|
||||
}
|
||||
}
|
||||
|
||||
if (!in_array($host, $platformHostnames)) {
|
||||
if (!in_array($host, $platformHostnames) && System::getEnv('_APP_OPTIONS_ROUTER_PROTECTION', 'enabled') === 'enabled') {
|
||||
throw new AppwriteException(AppwriteException::GENERAL_ACCESS_FORBIDDEN, 'Router protection does not allow accessing Appwrite over this domain. Please add it as custom domain to your project or disable _APP_OPTIONS_ROUTER_PROTECTION environment variable.', view: $errorView);
|
||||
}
|
||||
|
||||
|
||||
@@ -56,6 +56,9 @@ use Appwrite\Utopia\Response\Model\ColumnString;
|
||||
use Appwrite\Utopia\Response\Model\ColumnText;
|
||||
use Appwrite\Utopia\Response\Model\ColumnURL;
|
||||
use Appwrite\Utopia\Response\Model\ColumnVarchar;
|
||||
use Appwrite\Utopia\Response\Model\ConsoleOAuth2Provider;
|
||||
use Appwrite\Utopia\Response\Model\ConsoleOAuth2ProviderList;
|
||||
use Appwrite\Utopia\Response\Model\ConsoleOAuth2ProviderParameter;
|
||||
use Appwrite\Utopia\Response\Model\ConsoleVariables;
|
||||
use Appwrite\Utopia\Response\Model\Continent;
|
||||
use Appwrite\Utopia\Response\Model\Country;
|
||||
@@ -105,6 +108,47 @@ use Appwrite\Utopia\Response\Model\MigrationReport;
|
||||
use Appwrite\Utopia\Response\Model\Mock;
|
||||
use Appwrite\Utopia\Response\Model\MockNumber;
|
||||
use Appwrite\Utopia\Response\Model\None;
|
||||
use Appwrite\Utopia\Response\Model\OAuth2Amazon;
|
||||
use Appwrite\Utopia\Response\Model\OAuth2Apple;
|
||||
use Appwrite\Utopia\Response\Model\OAuth2Auth0;
|
||||
use Appwrite\Utopia\Response\Model\OAuth2Authentik;
|
||||
use Appwrite\Utopia\Response\Model\OAuth2Autodesk;
|
||||
use Appwrite\Utopia\Response\Model\OAuth2Bitbucket;
|
||||
use Appwrite\Utopia\Response\Model\OAuth2Bitly;
|
||||
use Appwrite\Utopia\Response\Model\OAuth2Box;
|
||||
use Appwrite\Utopia\Response\Model\OAuth2Dailymotion;
|
||||
use Appwrite\Utopia\Response\Model\OAuth2Discord;
|
||||
use Appwrite\Utopia\Response\Model\OAuth2Disqus;
|
||||
use Appwrite\Utopia\Response\Model\OAuth2Dropbox;
|
||||
use Appwrite\Utopia\Response\Model\OAuth2Etsy;
|
||||
use Appwrite\Utopia\Response\Model\OAuth2Facebook;
|
||||
use Appwrite\Utopia\Response\Model\OAuth2Figma;
|
||||
use Appwrite\Utopia\Response\Model\OAuth2FusionAuth;
|
||||
use Appwrite\Utopia\Response\Model\OAuth2GitHub;
|
||||
use Appwrite\Utopia\Response\Model\OAuth2Gitlab;
|
||||
use Appwrite\Utopia\Response\Model\OAuth2Google;
|
||||
use Appwrite\Utopia\Response\Model\OAuth2Keycloak;
|
||||
use Appwrite\Utopia\Response\Model\OAuth2Kick;
|
||||
use Appwrite\Utopia\Response\Model\OAuth2Linkedin;
|
||||
use Appwrite\Utopia\Response\Model\OAuth2Microsoft;
|
||||
use Appwrite\Utopia\Response\Model\OAuth2Notion;
|
||||
use Appwrite\Utopia\Response\Model\OAuth2Oidc;
|
||||
use Appwrite\Utopia\Response\Model\OAuth2Okta;
|
||||
use Appwrite\Utopia\Response\Model\OAuth2Paypal;
|
||||
use Appwrite\Utopia\Response\Model\OAuth2Podio;
|
||||
use Appwrite\Utopia\Response\Model\OAuth2ProviderList;
|
||||
use Appwrite\Utopia\Response\Model\OAuth2Salesforce;
|
||||
use Appwrite\Utopia\Response\Model\OAuth2Slack;
|
||||
use Appwrite\Utopia\Response\Model\OAuth2Spotify;
|
||||
use Appwrite\Utopia\Response\Model\OAuth2Stripe;
|
||||
use Appwrite\Utopia\Response\Model\OAuth2Tradeshift;
|
||||
use Appwrite\Utopia\Response\Model\OAuth2Twitch;
|
||||
use Appwrite\Utopia\Response\Model\OAuth2WordPress;
|
||||
use Appwrite\Utopia\Response\Model\OAuth2X;
|
||||
use Appwrite\Utopia\Response\Model\OAuth2Yahoo;
|
||||
use Appwrite\Utopia\Response\Model\OAuth2Yandex;
|
||||
use Appwrite\Utopia\Response\Model\OAuth2Zoho;
|
||||
use Appwrite\Utopia\Response\Model\OAuth2Zoom;
|
||||
use Appwrite\Utopia\Response\Model\Phone;
|
||||
use Appwrite\Utopia\Response\Model\PlatformAndroid;
|
||||
use Appwrite\Utopia\Response\Model\PlatformApple;
|
||||
@@ -350,6 +394,47 @@ Response::setModel(new Webhook());
|
||||
Response::setModel(new Key());
|
||||
Response::setModel(new DevKey());
|
||||
Response::setModel(new MockNumber());
|
||||
Response::setModel(new OAuth2GitHub());
|
||||
Response::setModel(new OAuth2Discord());
|
||||
Response::setModel(new OAuth2Figma());
|
||||
Response::setModel(new OAuth2Dropbox());
|
||||
Response::setModel(new OAuth2Dailymotion());
|
||||
Response::setModel(new OAuth2Bitbucket());
|
||||
Response::setModel(new OAuth2Bitly());
|
||||
Response::setModel(new OAuth2Box());
|
||||
Response::setModel(new OAuth2Autodesk());
|
||||
Response::setModel(new OAuth2Google());
|
||||
Response::setModel(new OAuth2Zoom());
|
||||
Response::setModel(new OAuth2Zoho());
|
||||
Response::setModel(new OAuth2Yandex());
|
||||
Response::setModel(new OAuth2X());
|
||||
Response::setModel(new OAuth2WordPress());
|
||||
Response::setModel(new OAuth2Twitch());
|
||||
Response::setModel(new OAuth2Stripe());
|
||||
Response::setModel(new OAuth2Spotify());
|
||||
Response::setModel(new OAuth2Slack());
|
||||
Response::setModel(new OAuth2Podio());
|
||||
Response::setModel(new OAuth2Notion());
|
||||
Response::setModel(new OAuth2Salesforce());
|
||||
Response::setModel(new OAuth2Yahoo());
|
||||
Response::setModel(new OAuth2Linkedin());
|
||||
Response::setModel(new OAuth2Disqus());
|
||||
Response::setModel(new OAuth2Amazon());
|
||||
Response::setModel(new OAuth2Etsy());
|
||||
Response::setModel(new OAuth2Facebook());
|
||||
Response::setModel(new OAuth2Tradeshift());
|
||||
Response::setModel(new OAuth2Paypal());
|
||||
Response::setModel(new OAuth2Gitlab());
|
||||
Response::setModel(new OAuth2Authentik());
|
||||
Response::setModel(new OAuth2Auth0());
|
||||
Response::setModel(new OAuth2FusionAuth());
|
||||
Response::setModel(new OAuth2Keycloak());
|
||||
Response::setModel(new OAuth2Oidc());
|
||||
Response::setModel(new OAuth2Okta());
|
||||
Response::setModel(new OAuth2Kick());
|
||||
Response::setModel(new OAuth2Apple());
|
||||
Response::setModel(new OAuth2Microsoft());
|
||||
Response::setModel(new OAuth2ProviderList());
|
||||
Response::setModel(new PolicyPasswordDictionary());
|
||||
Response::setModel(new PolicyPasswordHistory());
|
||||
Response::setModel(new PolicyPasswordPersonalData());
|
||||
@@ -398,6 +483,9 @@ Response::setModel(new Rule());
|
||||
Response::setModel(new Schedule());
|
||||
Response::setModel(new TemplateEmail());
|
||||
Response::setModel(new ConsoleVariables());
|
||||
Response::setModel(new ConsoleOAuth2ProviderParameter());
|
||||
Response::setModel(new ConsoleOAuth2Provider());
|
||||
Response::setModel(new ConsoleOAuth2ProviderList());
|
||||
Response::setModel(new MFAChallenge());
|
||||
Response::setModel(new MFARecoveryCodes());
|
||||
Response::setModel(new MFAType());
|
||||
|
||||
@@ -69,6 +69,7 @@
|
||||
"utopia-php/dsn": "0.2.1",
|
||||
"utopia-php/http": "0.34.*",
|
||||
"utopia-php/fetch": "0.5.*",
|
||||
"utopia-php/validators": "0.2.*",
|
||||
"utopia-php/image": "0.8.*",
|
||||
"utopia-php/locale": "0.8.*",
|
||||
"utopia-php/logger": "0.6.*",
|
||||
|
||||
Generated
+88
-86
@@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "c5ae97637fd0ec0a950044d1c33677ea",
|
||||
"content-hash": "805802552f7482eaeae4bdaa505ae982",
|
||||
"packages": [
|
||||
{
|
||||
"name": "adhocore/jwt",
|
||||
@@ -1996,16 +1996,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpseclib/phpseclib",
|
||||
"version": "3.0.51",
|
||||
"version": "3.0.52",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpseclib/phpseclib.git",
|
||||
"reference": "d59c94077f9c9915abb51ddb52ce85188ece1748"
|
||||
"reference": "2adaefc83df2ec548558307690f376dd7d4f4fce"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/d59c94077f9c9915abb51ddb52ce85188ece1748",
|
||||
"reference": "d59c94077f9c9915abb51ddb52ce85188ece1748",
|
||||
"url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/2adaefc83df2ec548558307690f376dd7d4f4fce",
|
||||
"reference": "2adaefc83df2ec548558307690f376dd7d4f4fce",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2086,7 +2086,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/phpseclib/phpseclib/issues",
|
||||
"source": "https://github.com/phpseclib/phpseclib/tree/3.0.51"
|
||||
"source": "https://github.com/phpseclib/phpseclib/tree/3.0.52"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -2102,7 +2102,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2026-04-10T01:33:53+00:00"
|
||||
"time": "2026-04-27T07:02:15+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/clock",
|
||||
@@ -2887,7 +2887,7 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-mbstring",
|
||||
"version": "v1.36.0",
|
||||
"version": "v1.37.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
||||
@@ -2948,7 +2948,7 @@
|
||||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.36.0"
|
||||
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.37.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -2972,7 +2972,7 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-php82",
|
||||
"version": "v1.36.0",
|
||||
"version": "v1.37.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-php82.git",
|
||||
@@ -3028,7 +3028,7 @@
|
||||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-php82/tree/v1.36.0"
|
||||
"source": "https://github.com/symfony/polyfill-php82/tree/v1.37.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -3052,7 +3052,7 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-php83",
|
||||
"version": "v1.36.0",
|
||||
"version": "v1.37.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-php83.git",
|
||||
@@ -3108,7 +3108,7 @@
|
||||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-php83/tree/v1.36.0"
|
||||
"source": "https://github.com/symfony/polyfill-php83/tree/v1.37.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -3132,16 +3132,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-php85",
|
||||
"version": "v1.36.0",
|
||||
"version": "v1.37.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-php85.git",
|
||||
"reference": "2c408a6bb0313e6001a83628dc5506100474254e"
|
||||
"reference": "fcfa4973a9917cef23f2e38774da74a2b7d115ee"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php85/zipball/2c408a6bb0313e6001a83628dc5506100474254e",
|
||||
"reference": "2c408a6bb0313e6001a83628dc5506100474254e",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php85/zipball/fcfa4973a9917cef23f2e38774da74a2b7d115ee",
|
||||
"reference": "fcfa4973a9917cef23f2e38774da74a2b7d115ee",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -3188,7 +3188,7 @@
|
||||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-php85/tree/v1.36.0"
|
||||
"source": "https://github.com/symfony/polyfill-php85/tree/v1.37.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -3208,7 +3208,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2026-04-10T16:50:15+00:00"
|
||||
"time": "2026-04-26T13:10:57+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/service-contracts",
|
||||
@@ -3658,16 +3658,16 @@
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/cli",
|
||||
"version": "0.23.1",
|
||||
"version": "0.23.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/cli.git",
|
||||
"reference": "8d1955b8bc4dc631f45d7c7df689ed7b63f70621"
|
||||
"reference": "145b91fef827853bcceaa3ab8ca2b1d6faaca2ab"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/cli/zipball/8d1955b8bc4dc631f45d7c7df689ed7b63f70621",
|
||||
"reference": "8d1955b8bc4dc631f45d7c7df689ed7b63f70621",
|
||||
"url": "https://api.github.com/repos/utopia-php/cli/zipball/145b91fef827853bcceaa3ab8ca2b1d6faaca2ab",
|
||||
"reference": "145b91fef827853bcceaa3ab8ca2b1d6faaca2ab",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -3703,9 +3703,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/cli/issues",
|
||||
"source": "https://github.com/utopia-php/cli/tree/0.23.1"
|
||||
"source": "https://github.com/utopia-php/cli/tree/0.23.2"
|
||||
},
|
||||
"time": "2026-04-05T15:27:35+00:00"
|
||||
"time": "2026-04-27T09:19:04+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/compression",
|
||||
@@ -4271,21 +4271,20 @@
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/http",
|
||||
"version": "0.34.21",
|
||||
"version": "0.34.24",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/http.git",
|
||||
"reference": "49a6bd3ea0d2966aa19cf707255d442675288a24"
|
||||
"reference": "d1eced0627c5a9fceddf53992ed97d664b810d33"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/http/zipball/49a6bd3ea0d2966aa19cf707255d442675288a24",
|
||||
"reference": "49a6bd3ea0d2966aa19cf707255d442675288a24",
|
||||
"url": "https://api.github.com/repos/utopia-php/http/zipball/d1eced0627c5a9fceddf53992ed97d664b810d33",
|
||||
"reference": "d1eced0627c5a9fceddf53992ed97d664b810d33",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-swoole": "*",
|
||||
"php": ">=8.2",
|
||||
"php": ">=8.3",
|
||||
"utopia-php/compression": "0.1.*",
|
||||
"utopia-php/di": "0.3.*",
|
||||
"utopia-php/servers": "0.3.*",
|
||||
@@ -4295,11 +4294,14 @@
|
||||
"require-dev": {
|
||||
"doctrine/instantiator": "^1.5",
|
||||
"laravel/pint": "1.*",
|
||||
"phpbench/phpbench": "^1.2",
|
||||
"phpstan/phpstan": "1.*",
|
||||
"phpunit/phpunit": "^9.5.25",
|
||||
"phpstan/phpstan": "^2.1",
|
||||
"phpunit/phpunit": "^12.0",
|
||||
"rector/rector": "^2.4",
|
||||
"swoole/ide-helper": "4.8.3"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-swoole": "Required to use the Swoole server adapter (\\Utopia\\Http\\Adapter\\Swoole\\Server)."
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
@@ -4319,9 +4321,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/http/issues",
|
||||
"source": "https://github.com/utopia-php/http/tree/0.34.21"
|
||||
"source": "https://github.com/utopia-php/http/tree/0.34.24"
|
||||
},
|
||||
"time": "2026-04-19T19:44:04+00:00"
|
||||
"time": "2026-04-24T12:16:53+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/image",
|
||||
@@ -4528,16 +4530,16 @@
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/migration",
|
||||
"version": "1.9.1",
|
||||
"version": "1.9.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/migration.git",
|
||||
"reference": "7a86aeadf182b63a9f4ceba7e137588b31c5d2e2"
|
||||
"reference": "111f6221d04578a6f721c23ac872002375f176ae"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/migration/zipball/7a86aeadf182b63a9f4ceba7e137588b31c5d2e2",
|
||||
"reference": "7a86aeadf182b63a9f4ceba7e137588b31c5d2e2",
|
||||
"url": "https://api.github.com/repos/utopia-php/migration/zipball/111f6221d04578a6f721c23ac872002375f176ae",
|
||||
"reference": "111f6221d04578a6f721c23ac872002375f176ae",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -4577,22 +4579,22 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/migration/issues",
|
||||
"source": "https://github.com/utopia-php/migration/tree/1.9.1"
|
||||
"source": "https://github.com/utopia-php/migration/tree/1.9.3"
|
||||
},
|
||||
"time": "2026-03-25T07:05:27+00:00"
|
||||
"time": "2026-04-22T07:13:26+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/mongo",
|
||||
"version": "1.0.2",
|
||||
"version": "1.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/mongo.git",
|
||||
"reference": "677a21c53f7a1316c528b4b45b3fce886cee7223"
|
||||
"reference": "73593682deee4696525a04e26524c1c1226e1530"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/mongo/zipball/677a21c53f7a1316c528b4b45b3fce886cee7223",
|
||||
"reference": "677a21c53f7a1316c528b4b45b3fce886cee7223",
|
||||
"url": "https://api.github.com/repos/utopia-php/mongo/zipball/73593682deee4696525a04e26524c1c1226e1530",
|
||||
"reference": "73593682deee4696525a04e26524c1c1226e1530",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -4638,9 +4640,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/mongo/issues",
|
||||
"source": "https://github.com/utopia-php/mongo/tree/1.0.2"
|
||||
"source": "https://github.com/utopia-php/mongo/tree/1.1.0"
|
||||
},
|
||||
"time": "2026-03-18T02:45:50+00:00"
|
||||
"time": "2026-04-24T06:15:10+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/platform",
|
||||
@@ -5182,16 +5184,16 @@
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/validators",
|
||||
"version": "0.2.0",
|
||||
"version": "0.2.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/validators.git",
|
||||
"reference": "30b6030a5b100fc1dff34506e5053759594b2a20"
|
||||
"reference": "5d7d494e64457cd4eb67fdcfd9481f2c89796aa6"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/validators/zipball/30b6030a5b100fc1dff34506e5053759594b2a20",
|
||||
"reference": "30b6030a5b100fc1dff34506e5053759594b2a20",
|
||||
"url": "https://api.github.com/repos/utopia-php/validators/zipball/5d7d494e64457cd4eb67fdcfd9481f2c89796aa6",
|
||||
"reference": "5d7d494e64457cd4eb67fdcfd9481f2c89796aa6",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -5221,9 +5223,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/validators/issues",
|
||||
"source": "https://github.com/utopia-php/validators/tree/0.2.0"
|
||||
"source": "https://github.com/utopia-php/validators/tree/0.2.2"
|
||||
},
|
||||
"time": "2026-01-13T09:16:51+00:00"
|
||||
"time": "2026-04-27T16:30:24+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/vcs",
|
||||
@@ -5464,16 +5466,16 @@
|
||||
"packages-dev": [
|
||||
{
|
||||
"name": "appwrite/sdk-generator",
|
||||
"version": "1.20",
|
||||
"version": "1.24.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/appwrite/sdk-generator.git",
|
||||
"reference": "525f0630520c95100fcdfb63c9dac859c1d02588"
|
||||
"reference": "6d4d26659bc7a1c347c1d4d8dae3b77b5562e0cb"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/525f0630520c95100fcdfb63c9dac859c1d02588",
|
||||
"reference": "525f0630520c95100fcdfb63c9dac859c1d02588",
|
||||
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/6d4d26659bc7a1c347c1d4d8dae3b77b5562e0cb",
|
||||
"reference": "6d4d26659bc7a1c347c1d4d8dae3b77b5562e0cb",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -5509,9 +5511,9 @@
|
||||
"description": "Appwrite PHP library for generating API SDKs for multiple programming languages and platforms",
|
||||
"support": {
|
||||
"issues": "https://github.com/appwrite/sdk-generator/issues",
|
||||
"source": "https://github.com/appwrite/sdk-generator/tree/1.20"
|
||||
"source": "https://github.com/appwrite/sdk-generator/tree/1.24.0"
|
||||
},
|
||||
"time": "2026-04-20T05:45:00+00:00"
|
||||
"time": "2026-04-24T12:50:05+00:00"
|
||||
},
|
||||
{
|
||||
"name": "brianium/paratest",
|
||||
@@ -5793,16 +5795,16 @@
|
||||
},
|
||||
{
|
||||
"name": "laravel/pint",
|
||||
"version": "v1.29.0",
|
||||
"version": "v1.29.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laravel/pint.git",
|
||||
"reference": "bdec963f53172c5e36330f3a400604c69bf02d39"
|
||||
"reference": "0770e9b7fafd50d4586881d456d6eb41c9247a80"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laravel/pint/zipball/bdec963f53172c5e36330f3a400604c69bf02d39",
|
||||
"reference": "bdec963f53172c5e36330f3a400604c69bf02d39",
|
||||
"url": "https://api.github.com/repos/laravel/pint/zipball/0770e9b7fafd50d4586881d456d6eb41c9247a80",
|
||||
"reference": "0770e9b7fafd50d4586881d456d6eb41c9247a80",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -5813,14 +5815,14 @@
|
||||
"php": "^8.2.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"friendsofphp/php-cs-fixer": "^3.94.2",
|
||||
"illuminate/view": "^12.54.1",
|
||||
"larastan/larastan": "^3.9.3",
|
||||
"laravel-zero/framework": "^12.0.5",
|
||||
"friendsofphp/php-cs-fixer": "^3.95.1",
|
||||
"illuminate/view": "^12.56.0",
|
||||
"larastan/larastan": "^3.9.6",
|
||||
"laravel-zero/framework": "^12.1.0",
|
||||
"mockery/mockery": "^1.6.12",
|
||||
"nunomaduro/termwind": "^2.4.0",
|
||||
"pestphp/pest": "^3.8.6",
|
||||
"shipfastlabs/agent-detector": "^1.1.0"
|
||||
"shipfastlabs/agent-detector": "^1.1.3"
|
||||
},
|
||||
"bin": [
|
||||
"builds/pint"
|
||||
@@ -5857,7 +5859,7 @@
|
||||
"issues": "https://github.com/laravel/pint/issues",
|
||||
"source": "https://github.com/laravel/pint"
|
||||
},
|
||||
"time": "2026-03-12T15:51:39+00:00"
|
||||
"time": "2026-04-20T15:26:14+00:00"
|
||||
},
|
||||
{
|
||||
"name": "matthiasmullie/minify",
|
||||
@@ -6220,11 +6222,11 @@
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan",
|
||||
"version": "2.1.50",
|
||||
"version": "2.1.51",
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/d452086fb4cf648c6b2d8cf3b639351f79e4f3e2",
|
||||
"reference": "d452086fb4cf648c6b2d8cf3b639351f79e4f3e2",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/dc3b523c45e714c70de2ac5113b958223b55dc59",
|
||||
"reference": "dc3b523c45e714c70de2ac5113b958223b55dc59",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -6269,7 +6271,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2026-04-17T13:10:32+00:00"
|
||||
"time": "2026-04-21T18:22:01+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-code-coverage",
|
||||
@@ -7779,7 +7781,7 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-ctype",
|
||||
"version": "v1.36.0",
|
||||
"version": "v1.37.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-ctype.git",
|
||||
@@ -7838,7 +7840,7 @@
|
||||
"portable"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.36.0"
|
||||
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.37.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -7862,16 +7864,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-intl-grapheme",
|
||||
"version": "v1.36.0",
|
||||
"version": "v1.37.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-intl-grapheme.git",
|
||||
"reference": "ad1b7b9092976d6c948b8a187cec9faaea9ec1df"
|
||||
"reference": "4864388bfbd3001ce88e234fab652acd91fdc57e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/ad1b7b9092976d6c948b8a187cec9faaea9ec1df",
|
||||
"reference": "ad1b7b9092976d6c948b8a187cec9faaea9ec1df",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/4864388bfbd3001ce88e234fab652acd91fdc57e",
|
||||
"reference": "4864388bfbd3001ce88e234fab652acd91fdc57e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -7920,7 +7922,7 @@
|
||||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.36.0"
|
||||
"source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.37.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -7940,11 +7942,11 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2026-04-10T16:19:22+00:00"
|
||||
"time": "2026-04-26T13:13:48+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-intl-normalizer",
|
||||
"version": "v1.36.0",
|
||||
"version": "v1.37.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-intl-normalizer.git",
|
||||
@@ -8005,7 +8007,7 @@
|
||||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.36.0"
|
||||
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.37.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -8029,7 +8031,7 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-php81",
|
||||
"version": "v1.36.0",
|
||||
"version": "v1.37.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-php81.git",
|
||||
@@ -8085,7 +8087,7 @@
|
||||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-php81/tree/v1.36.0"
|
||||
"source": "https://github.com/symfony/polyfill-php81/tree/v1.37.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
||||
@@ -247,6 +247,8 @@ services:
|
||||
- _APP_CUSTOM_DOMAIN_DENY_LIST
|
||||
- _APP_TRUSTED_HEADERS
|
||||
- _APP_MIGRATION_HOST
|
||||
- _TESTS_OAUTH2_GITHUB_CLIENT_ID
|
||||
- _TESTS_OAUTH2_GITHUB_CLIENT_SECRET
|
||||
extra_hosts:
|
||||
- "host.docker.internal:host-gateway"
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
List all OAuth2 providers supported by the Appwrite server, along with the parameters required to configure each provider. The response excludes mock providers but includes sandbox providers.
|
||||
@@ -0,0 +1,226 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Auth\OAuth2;
|
||||
|
||||
use Appwrite\Auth\OAuth2;
|
||||
|
||||
// Reference Material
|
||||
// https://fusionauth.io/docs/lifecycle/authenticate-users/oauth/endpoints
|
||||
|
||||
class FusionAuth extends OAuth2
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected array $scopes = [
|
||||
'openid',
|
||||
'profile',
|
||||
'email',
|
||||
'offline_access'
|
||||
];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected array $user = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected array $tokens = [];
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'fusionauth';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return 'https://' . $this->getFusionAuthDomain() . '/oauth2/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->getFusionAuthDomain() . '/oauth2/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->getFusionAuthDomain() . '/oauth2/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 '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the User email is verified
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if ($user['email_verified'] ?? false) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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->getFusionAuthDomain() . '/oauth2/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 $secret['clientSecret'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the FusionAuth Domain from the JSON stored in appSecret
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getFusionAuthDomain(): string
|
||||
{
|
||||
$secret = $this->getAppSecret();
|
||||
return $secret['fusionAuthDomain'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace Appwrite\Auth\OAuth2;
|
||||
|
||||
use Appwrite\Auth\OAuth2;
|
||||
use Utopia\Fetch\Client as FetchClient;
|
||||
|
||||
class Github extends OAuth2
|
||||
{
|
||||
@@ -219,4 +220,34 @@ class Github extends OAuth2
|
||||
$repository = \json_decode($repository, true);
|
||||
return $repository;
|
||||
}
|
||||
|
||||
public function verifyCredentials(): void
|
||||
{
|
||||
$client = new FetchClient();
|
||||
$client->addHeader('Accept', 'application/json');
|
||||
|
||||
$response = $client->fetch(
|
||||
url: 'https://github.com/login/oauth/access_token',
|
||||
method: FetchClient::METHOD_POST,
|
||||
query: [
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->appSecret,
|
||||
'code' => 'intentionally-invalid-code',
|
||||
'redirect_uri' => 'intentionally-invalid-redirect',
|
||||
]
|
||||
);
|
||||
|
||||
$json = \json_decode($response->getBody(), true);
|
||||
|
||||
if (isset($json['error']) && $json['error'] === "Not Found") {
|
||||
throw new \Exception('GitHub application with provided Client ID is does not exist.');
|
||||
}
|
||||
|
||||
if (isset($json['error']) && $json['error'] === "incorrect_client_credentials") {
|
||||
throw new \Exception('GitHub application with provided Client ID is valid, but the provided Client Secret is incorrect.');
|
||||
}
|
||||
|
||||
// We still expect error, like redirect_uri_mismatch or bad_verification_code,
|
||||
// but that indicates valid credentials
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,249 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Auth\OAuth2;
|
||||
|
||||
use Appwrite\Auth\OAuth2;
|
||||
|
||||
// Reference Material
|
||||
// https://www.keycloak.org/docs/latest/securing_apps/#_oidc
|
||||
|
||||
class Keycloak extends OAuth2
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected array $scopes = [
|
||||
'openid',
|
||||
'profile',
|
||||
'email',
|
||||
'offline_access'
|
||||
];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected array $user = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected array $tokens = [];
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'keycloak';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return $this->getRealmBaseURL() . '/protocol/openid-connect/auth?' . \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',
|
||||
$this->getRealmBaseURL() . '/protocol/openid-connect/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',
|
||||
$this->getRealmBaseURL() . '/protocol/openid-connect/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 '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the User email is verified
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if ($user['email_verified'] ?? false) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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', $this->getRealmBaseURL() . '/protocol/openid-connect/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 $secret['clientSecret'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the Keycloak Domain from the JSON stored in appSecret
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getKeycloakDomain(): string
|
||||
{
|
||||
$secret = $this->getAppSecret();
|
||||
return $secret['keycloakDomain'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the Keycloak Realm from the JSON stored in appSecret
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getKeycloakRealm(): string
|
||||
{
|
||||
$secret = $this->getAppSecret();
|
||||
return $secret['keycloakRealm'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the realm-scoped base URL: `https://{domain}/realms/{realm}`.
|
||||
* Keycloak realm names allow spaces and other characters that must be
|
||||
* percent-encoded in URLs (e.g. `my realm` → `my%20realm`).
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getRealmBaseURL(): string
|
||||
{
|
||||
return 'https://' . $this->getKeycloakDomain() . '/realms/' . \rawurlencode($this->getKeycloakRealm());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,230 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Auth\OAuth2;
|
||||
|
||||
use Appwrite\Auth\OAuth2;
|
||||
|
||||
// Reference Material
|
||||
// https://docs.kick.com/getting-started/generating-tokens-oauth2-flow
|
||||
// https://docs.kick.com/getting-started/scopes
|
||||
|
||||
class Kick extends OAuth2
|
||||
{
|
||||
private const PKCE_STATE_KEY = '_pkce';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected array $user = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected array $tokens = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected array $scopes = [
|
||||
'user:read',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private string $pkceVerifier = '';
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'kick';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
$state = $this->state;
|
||||
$state[self::PKCE_STATE_KEY] = $this->getPKCEVerifier();
|
||||
|
||||
return 'https://id.kick.com/oauth/authorize?' . \http_build_query([
|
||||
'response_type' => 'code',
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
'state' => \json_encode($state),
|
||||
'code_challenge' => $this->getPKCEChallenge(),
|
||||
'code_challenge_method' => 'S256',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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://id.kick.com/oauth/token',
|
||||
$headers,
|
||||
\http_build_query([
|
||||
'grant_type' => 'authorization_code',
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->appSecret,
|
||||
'redirect_uri' => $this->callback,
|
||||
'code_verifier' => $this->getPKCEVerifier(),
|
||||
'code' => $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://id.kick.com/oauth/token',
|
||||
$headers,
|
||||
\http_build_query([
|
||||
'grant_type' => 'refresh_token',
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->appSecret,
|
||||
'refresh_token' => $refreshToken,
|
||||
])
|
||||
), 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);
|
||||
|
||||
return isset($user['user_id']) ? (string)$user['user_id'] : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
return $user['email'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the OAuth email is verified.
|
||||
*
|
||||
* Kick only returns an email when the user has granted the `user:read`
|
||||
* scope and the account email is verified, so a non-empty email is
|
||||
* treated as verified.
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
{
|
||||
return !empty($this->getUserEmail($accessToken));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
return $user['name'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken): array
|
||||
{
|
||||
if (empty($this->user)) {
|
||||
$headers = ['Authorization: Bearer ' . $accessToken];
|
||||
$response = \json_decode($this->request(
|
||||
'GET',
|
||||
'https://api.kick.com/public/v1/users',
|
||||
$headers
|
||||
), true);
|
||||
|
||||
$this->user = $response['data'][0] ?? [];
|
||||
}
|
||||
|
||||
return $this->user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the PKCE verifier from the state on the callback so the same
|
||||
* value generated in getLoginURL() can be sent to the token endpoint.
|
||||
*
|
||||
* @param string $state
|
||||
*
|
||||
* @return array<string, mixed>|null
|
||||
*/
|
||||
public function parseState(string $state): ?array
|
||||
{
|
||||
$parsed = \json_decode($state, true);
|
||||
|
||||
if (!\is_array($parsed)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$verifier = $parsed[self::PKCE_STATE_KEY] ?? null;
|
||||
if (\is_string($verifier)) {
|
||||
$this->pkceVerifier = $verifier;
|
||||
}
|
||||
|
||||
unset($parsed[self::PKCE_STATE_KEY]);
|
||||
|
||||
return $parsed;
|
||||
}
|
||||
|
||||
private function getPKCEVerifier(): string
|
||||
{
|
||||
if ($this->pkceVerifier === '') {
|
||||
$this->pkceVerifier = \rtrim(\strtr(\base64_encode(\random_bytes(64)), '+/', '-_'), '=');
|
||||
}
|
||||
|
||||
return $this->pkceVerifier;
|
||||
}
|
||||
|
||||
private function getPKCEChallenge(): string
|
||||
{
|
||||
return \rtrim(\strtr(\base64_encode(\hash('sha256', $this->getPKCEVerifier(), true)), '+/', '-_'), '=');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Console\Http\OAuth2Providers;
|
||||
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Base as OAuth2Base;
|
||||
use Appwrite\SDK\AuthType;
|
||||
use Appwrite\SDK\ContentType;
|
||||
use Appwrite\SDK\Method;
|
||||
use Appwrite\SDK\Response as SDKResponse;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Platform\Action;
|
||||
use Utopia\Platform\Scope\HTTP;
|
||||
|
||||
class XList extends Action
|
||||
{
|
||||
use HTTP;
|
||||
|
||||
public static function getName(): string
|
||||
{
|
||||
return 'listOAuth2Providers';
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this
|
||||
->setHttpMethod(Action::HTTP_REQUEST_METHOD_GET)
|
||||
->setHttpPath('/v1/console/oauth2-providers')
|
||||
->desc('List OAuth2 providers')
|
||||
->groups(['api'])
|
||||
->label('scope', 'public')
|
||||
->label('sdk', new Method(
|
||||
namespace: 'console',
|
||||
group: 'console',
|
||||
name: 'listOAuth2Providers',
|
||||
description: '/docs/references/console/list-oauth2-providers.md',
|
||||
auth: [AuthType::ADMIN],
|
||||
responses: [
|
||||
new SDKResponse(
|
||||
code: Response::STATUS_CODE_OK,
|
||||
model: Response::MODEL_CONSOLE_OAUTH2_PROVIDER_LIST,
|
||||
)
|
||||
],
|
||||
contentType: ContentType::JSON
|
||||
))
|
||||
->inject('response')
|
||||
->callback($this->action(...));
|
||||
}
|
||||
|
||||
public function action(Response $response): void
|
||||
{
|
||||
$providersConfig = Config::getParam('oAuthProviders', []);
|
||||
$actions = OAuth2Base::getProviderActions();
|
||||
|
||||
$providers = [];
|
||||
foreach ($actions as $providerId => $updateClass) {
|
||||
$config = $providersConfig[$providerId] ?? null;
|
||||
if ($config === null) {
|
||||
continue;
|
||||
}
|
||||
if (!($config['enabled'] ?? false)) {
|
||||
continue;
|
||||
}
|
||||
if ($config['mock'] ?? false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$providers[] = new Document([
|
||||
'$id' => $providerId,
|
||||
'parameters' => $updateClass::getParameters(),
|
||||
]);
|
||||
}
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'total' => \count($providers),
|
||||
'oAuth2Providers' => $providers,
|
||||
]), Response::MODEL_CONSOLE_OAUTH2_PROVIDER_LIST);
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ namespace Appwrite\Platform\Modules\Console\Services;
|
||||
use Appwrite\Platform\Modules\Console\Http\Assistant\Create as CreateAssistantQuery;
|
||||
use Appwrite\Platform\Modules\Console\Http\Init\API;
|
||||
use Appwrite\Platform\Modules\Console\Http\Init\Web;
|
||||
use Appwrite\Platform\Modules\Console\Http\OAuth2Providers\XList as ListOAuth2Providers;
|
||||
use Appwrite\Platform\Modules\Console\Http\Redirects\Auth\Get as RedirectAuth;
|
||||
use Appwrite\Platform\Modules\Console\Http\Redirects\Card\Get as RedirectCard;
|
||||
use Appwrite\Platform\Modules\Console\Http\Redirects\Invite\Get as RedirectInvite;
|
||||
@@ -28,6 +29,7 @@ class Http extends Service
|
||||
$this->addAction(Web::getName(), new Web());
|
||||
|
||||
$this->addAction(GetVariables::getName(), new GetVariables());
|
||||
$this->addAction(ListOAuth2Providers::getName(), new ListOAuth2Providers());
|
||||
$this->addAction(CreateAssistantQuery::getName(), new CreateAssistantQuery());
|
||||
$this->addAction(GetResourceAvailability::getName(), new GetResourceAvailability());
|
||||
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Amazon;
|
||||
|
||||
use Appwrite\Auth\OAuth2\Amazon;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Base;
|
||||
use Appwrite\Utopia\Response;
|
||||
|
||||
class Update extends Base
|
||||
{
|
||||
public static function getProviderId(): string
|
||||
{
|
||||
return 'amazon';
|
||||
}
|
||||
|
||||
public static function getProviderClass(): string
|
||||
{
|
||||
return Amazon::class;
|
||||
}
|
||||
|
||||
public static function getProviderLabel(): string
|
||||
{
|
||||
return 'Amazon';
|
||||
}
|
||||
|
||||
public static function getProviderSDKMethod(): string
|
||||
{
|
||||
return 'updateOAuth2Amazon';
|
||||
}
|
||||
|
||||
public static function getResponseModel(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_AMAZON;
|
||||
}
|
||||
|
||||
public static function getClientIdName(): string
|
||||
{
|
||||
return 'Client ID';
|
||||
}
|
||||
|
||||
public static function getClientIdExample(): string
|
||||
{
|
||||
return 'amzn1.application-oa2-client.87400c00000000000000000000063d5b2';
|
||||
}
|
||||
|
||||
public static function getClientSecretName(): string
|
||||
{
|
||||
return 'Client Secret';
|
||||
}
|
||||
|
||||
public static function getClientSecretExample(): string
|
||||
{
|
||||
return '79ffe4000000000000000000000000000000000000000000000000000002de55';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Apple;
|
||||
|
||||
use Appwrite\Auth\OAuth2\Apple;
|
||||
use Appwrite\Event\Event as QueueEvent;
|
||||
use Appwrite\Platform\Action;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Base;
|
||||
use Appwrite\SDK\AuthType;
|
||||
use Appwrite\SDK\Method;
|
||||
use Appwrite\SDK\Response as SDKResponse;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\Nullable;
|
||||
use Utopia\Validator\Text;
|
||||
|
||||
class Update extends Base
|
||||
{
|
||||
public static function getProviderId(): string
|
||||
{
|
||||
return 'apple';
|
||||
}
|
||||
|
||||
public static function getProviderClass(): string
|
||||
{
|
||||
return Apple::class;
|
||||
}
|
||||
|
||||
public static function getProviderLabel(): string
|
||||
{
|
||||
return 'Apple';
|
||||
}
|
||||
|
||||
public static function getProviderSDKMethod(): string
|
||||
{
|
||||
return 'updateOAuth2Apple';
|
||||
}
|
||||
|
||||
public static function getResponseModel(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_APPLE;
|
||||
}
|
||||
|
||||
public static function getClientIdParamName(): string
|
||||
{
|
||||
return 'serviceId';
|
||||
}
|
||||
|
||||
public static function getClientIdName(): string
|
||||
{
|
||||
return 'Service ID';
|
||||
}
|
||||
|
||||
public static function getClientIdExample(): string
|
||||
{
|
||||
return 'ip.appwrite.app.web';
|
||||
}
|
||||
|
||||
public static function getClientSecretName(): string
|
||||
{
|
||||
// Apple does not use a single clientSecret param. Returning an empty
|
||||
// string causes the default getParameters() to skip it; the override
|
||||
// below adds the three real fields (keyId, teamId, p8File).
|
||||
return '';
|
||||
}
|
||||
|
||||
public static function getClientSecretExample(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public static function getParameters(): array
|
||||
{
|
||||
return [
|
||||
[
|
||||
'$id' => static::getClientIdParamName(),
|
||||
'name' => static::getClientIdName(),
|
||||
'example' => static::getClientIdExample(),
|
||||
'hint' => '',
|
||||
],
|
||||
[
|
||||
'$id' => 'keyId',
|
||||
'name' => 'Key ID',
|
||||
'example' => 'P4000000N8',
|
||||
'hint' => '',
|
||||
],
|
||||
[
|
||||
'$id' => 'teamId',
|
||||
'name' => 'Team ID',
|
||||
'example' => 'D4000000R6',
|
||||
'hint' => '',
|
||||
],
|
||||
[
|
||||
'$id' => 'p8File',
|
||||
'name' => 'P8 File',
|
||||
'example' => '-----BEGIN PRIVATE KEY-----MIGTAg...jy2Xbna-----END PRIVATE KEY-----',
|
||||
'hint' => '',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$providerId = static::getProviderId();
|
||||
$providerLabel = static::getProviderLabel();
|
||||
|
||||
$this
|
||||
->setHttpMethod(Action::HTTP_REQUEST_METHOD_PATCH)
|
||||
->setHttpPath('/v1/project/oauth2/' . $providerId)
|
||||
->desc('Update project OAuth2 ' . $providerLabel)
|
||||
->groups(['api', 'project'])
|
||||
->label('scope', 'oauth2.write')
|
||||
->label('event', 'oauth2.[providerId].update')
|
||||
->label('audits.event', 'project.oauth2.[providerId].update')
|
||||
->label('audits.resource', 'project.oauth2/{response.$id}')
|
||||
->label('sdk', new Method(
|
||||
namespace: 'project',
|
||||
group: 'oauth2',
|
||||
name: static::getProviderSDKMethod(),
|
||||
description: 'Update the project OAuth2 ' . $providerLabel . ' configuration.',
|
||||
auth: [AuthType::ADMIN, AuthType::KEY],
|
||||
responses: [
|
||||
new SDKResponse(
|
||||
code: Response::STATUS_CODE_OK,
|
||||
model: static::getResponseModel(),
|
||||
)
|
||||
],
|
||||
))
|
||||
->param(static::getClientIdParamName(), null, new Nullable(new Text(256, 0)), static::getClientIdDescription(), optional: true)
|
||||
->param('keyId', null, new Nullable(new Text(256, 0)), '\'Key ID\' of Apple OAuth2 app. For example: P4000000N8', optional: true)
|
||||
->param('teamId', null, new Nullable(new Text(256, 0)), '\'Team ID\' of Apple OAuth2 app. For example: D4000000R6', optional: true)
|
||||
->param('p8File', null, new Nullable(new Text(4096, 0)), 'Contents of the Apple OAuth2 app .p8 private key file. The secret key wrapped by the PEM markers is 200 characters long. For example: -----BEGIN PRIVATE KEY-----MIGTAg...jy2Xbna-----END PRIVATE KEY-----', optional: true)
|
||||
->param('enabled', null, new Nullable(new Boolean()), 'OAuth2 sign-in method status. Set to true to enable new session creation. Setting to true will trigger end-to-end credentials validation, and will throw if the credentials are invalid.', true)
|
||||
->inject('response')
|
||||
->inject('dbForPlatform')
|
||||
->inject('project')
|
||||
->inject('authorization')
|
||||
->inject('queueForEvents')
|
||||
->callback($this->handle(...));
|
||||
}
|
||||
|
||||
public function buildReadResponse(Document $project): Document
|
||||
{
|
||||
$providerId = static::getProviderId();
|
||||
$oAuthProviders = $project->getAttribute('oAuthProviders', []);
|
||||
|
||||
return new Document([
|
||||
'$id' => $providerId,
|
||||
'enabled' => $oAuthProviders[$providerId . 'Enabled'] ?? false,
|
||||
static::getClientIdParamName() => $oAuthProviders[$providerId . 'Appid'] ?? '',
|
||||
'keyId' => '',
|
||||
'teamId' => '',
|
||||
'p8File' => '',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom callback used instead of the parent's `action()` because Apple's
|
||||
* client secret is composed of three fields (.p8 file contents, Key ID and
|
||||
* Team ID) that must be JSON-encoded to match the shape Apple's OAuth2
|
||||
* adapter expects in getAppSecret(). The method is named differently to
|
||||
* avoid an LSP-incompatible override of Base::action().
|
||||
*/
|
||||
public function handle(
|
||||
?string $serviceId,
|
||||
?string $keyId,
|
||||
?string $teamId,
|
||||
?string $p8File,
|
||||
?bool $enabled,
|
||||
Response $response,
|
||||
Database $dbForPlatform,
|
||||
Document $project,
|
||||
Authorization $authorization,
|
||||
QueueEvent $queueForEvents
|
||||
): void {
|
||||
$providerId = static::getProviderId();
|
||||
$queueForEvents->setParam('providerId', $providerId);
|
||||
|
||||
// The secret is stored as JSON `{"p8": "...", "keyID": "...", "teamID": "..."}`
|
||||
// to match the shape Apple's OAuth2 adapter expects in getAppSecret().
|
||||
// Merge new values with what's already stored so that submitting only
|
||||
// some of the fields leaves the rest untouched.
|
||||
$encodedSecret = null;
|
||||
if (!\is_null($keyId) || !\is_null($teamId) || !\is_null($p8File)) {
|
||||
$storedRaw = $project->getAttribute('oAuthProviders', [])[$providerId . 'Secret'] ?? '';
|
||||
$existing = [];
|
||||
if (!empty($storedRaw)) {
|
||||
$existing = \json_decode($storedRaw, true) ?: [];
|
||||
}
|
||||
$encodedSecret = \json_encode([
|
||||
'p8' => $p8File ?? ($existing['p8'] ?? ''),
|
||||
'keyID' => $keyId ?? ($existing['keyID'] ?? ''),
|
||||
'teamID' => $teamId ?? ($existing['teamID'] ?? ''),
|
||||
]);
|
||||
}
|
||||
|
||||
$project = $this->persistCredentials($project, $dbForPlatform, $authorization, $serviceId, $encodedSecret, $enabled);
|
||||
|
||||
// Reuse buildReadResponse to keep PATCH/GET shapes identical and
|
||||
// guarantee keyId/teamId/p8File are write-only on every response path.
|
||||
$response->dynamic($this->buildReadResponse($project), static::getResponseModel());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Auth0;
|
||||
|
||||
use Appwrite\Auth\OAuth2\Auth0;
|
||||
use Appwrite\Event\Event as QueueEvent;
|
||||
use Appwrite\Platform\Action;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Base;
|
||||
use Appwrite\SDK\AuthType;
|
||||
use Appwrite\SDK\Method;
|
||||
use Appwrite\SDK\Response as SDKResponse;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\Nullable;
|
||||
use Utopia\Validator\Text;
|
||||
|
||||
class Update extends Base
|
||||
{
|
||||
public static function getProviderId(): string
|
||||
{
|
||||
return 'auth0';
|
||||
}
|
||||
|
||||
public static function getProviderClass(): string
|
||||
{
|
||||
return Auth0::class;
|
||||
}
|
||||
|
||||
public static function getProviderLabel(): string
|
||||
{
|
||||
return 'Auth0';
|
||||
}
|
||||
|
||||
public static function getProviderSDKMethod(): string
|
||||
{
|
||||
return 'updateOAuth2Auth0';
|
||||
}
|
||||
|
||||
public static function getResponseModel(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_AUTH0;
|
||||
}
|
||||
|
||||
public static function getClientIdName(): string
|
||||
{
|
||||
return 'Client ID';
|
||||
}
|
||||
|
||||
public static function getClientIdExample(): string
|
||||
{
|
||||
return 'OaOkIA000000000000000000005KLSYq';
|
||||
}
|
||||
|
||||
public static function getClientSecretName(): string
|
||||
{
|
||||
return 'Client Secret';
|
||||
}
|
||||
|
||||
public static function getClientSecretExample(): string
|
||||
{
|
||||
return 'zXz0000-00000000000000000000000000000-00000000000000000000PJafnF';
|
||||
}
|
||||
|
||||
public static function getParameters(): array
|
||||
{
|
||||
return \array_merge(parent::getParameters(), [
|
||||
[
|
||||
'$id' => 'endpoint',
|
||||
'name' => 'Domain',
|
||||
'example' => 'example.us.auth0.com',
|
||||
'hint' => '',
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$providerId = static::getProviderId();
|
||||
$providerLabel = static::getProviderLabel();
|
||||
|
||||
$this
|
||||
->setHttpMethod(Action::HTTP_REQUEST_METHOD_PATCH)
|
||||
->setHttpPath('/v1/project/oauth2/' . $providerId)
|
||||
->desc('Update project OAuth2 ' . $providerLabel)
|
||||
->groups(['api', 'project'])
|
||||
->label('scope', 'oauth2.write')
|
||||
->label('event', 'oauth2.[providerId].update')
|
||||
->label('audits.event', 'project.oauth2.[providerId].update')
|
||||
->label('audits.resource', 'project.oauth2/{response.$id}')
|
||||
->label('sdk', new Method(
|
||||
namespace: 'project',
|
||||
group: 'oauth2',
|
||||
name: static::getProviderSDKMethod(),
|
||||
description: 'Update the project OAuth2 ' . $providerLabel . ' configuration.',
|
||||
auth: [AuthType::ADMIN, AuthType::KEY],
|
||||
responses: [
|
||||
new SDKResponse(
|
||||
code: Response::STATUS_CODE_OK,
|
||||
model: static::getResponseModel(),
|
||||
)
|
||||
],
|
||||
))
|
||||
->param(static::getClientIdParamName(), null, new Nullable(new Text(256, 0)), static::getClientIdDescription(), optional: true)
|
||||
->param(static::getClientSecretParamName(), null, new Nullable(new Text(512, 0)), static::getClientSecretDescription(), optional: true)
|
||||
->param('endpoint', null, new Nullable(new Text(256, 0)), 'Domain of Auth0 instance. For example: example.us.auth0.com', optional: true)
|
||||
->param('enabled', null, new Nullable(new Boolean()), 'OAuth2 sign-in method status. Set to true to enable new session creation. Setting to true will trigger end-to-end credentials validation, and will throw if the credentials are invalid.', true)
|
||||
->inject('response')
|
||||
->inject('dbForPlatform')
|
||||
->inject('project')
|
||||
->inject('authorization')
|
||||
->inject('queueForEvents')
|
||||
->callback($this->handle(...));
|
||||
}
|
||||
|
||||
public function buildReadResponse(Document $project): Document
|
||||
{
|
||||
$providerId = static::getProviderId();
|
||||
$oAuthProviders = $project->getAttribute('oAuthProviders', []);
|
||||
$decoded = $this->decodeStoredSecret($project);
|
||||
|
||||
return new Document([
|
||||
'$id' => $providerId,
|
||||
'enabled' => $oAuthProviders[$providerId . 'Enabled'] ?? false,
|
||||
static::getClientIdParamName() => $oAuthProviders[$providerId . 'Appid'] ?? '',
|
||||
static::getClientSecretParamName() => '',
|
||||
'endpoint' => $decoded['auth0Domain'] ?? '',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom callback used instead of the parent's `action()` because Auth0
|
||||
* takes an additional optional `endpoint` parameter. The method is named
|
||||
* differently to avoid an LSP-incompatible override of Base::action().
|
||||
*/
|
||||
public function handle(
|
||||
?string $clientId,
|
||||
?string $clientSecret,
|
||||
?string $endpoint,
|
||||
?bool $enabled,
|
||||
Response $response,
|
||||
Database $dbForPlatform,
|
||||
Document $project,
|
||||
Authorization $authorization,
|
||||
QueueEvent $queueForEvents
|
||||
): void {
|
||||
$providerId = static::getProviderId();
|
||||
$queueForEvents->setParam('providerId', $providerId);
|
||||
|
||||
// The secret is stored as JSON `{"clientSecret": "...", "auth0Domain": "..."}`
|
||||
// to match the shape Auth0's OAuth2 adapter expects (getAuth0Domain()).
|
||||
// Merge new values with existing storage so that submitting only one of
|
||||
// `clientSecret`/`endpoint` leaves the other untouched.
|
||||
$encodedSecret = null;
|
||||
if (!\is_null($clientSecret) || !\is_null($endpoint)) {
|
||||
$storedRaw = $project->getAttribute('oAuthProviders', [])[$providerId . 'Secret'] ?? '';
|
||||
$existing = [];
|
||||
if (!empty($storedRaw)) {
|
||||
$existing = \json_decode($storedRaw, true) ?: [];
|
||||
}
|
||||
$encodedSecret = \json_encode([
|
||||
'clientSecret' => $clientSecret ?? ($existing['clientSecret'] ?? ''),
|
||||
'auth0Domain' => $endpoint ?? ($existing['auth0Domain'] ?? ''),
|
||||
]);
|
||||
}
|
||||
|
||||
$project = $this->persistCredentials($project, $dbForPlatform, $authorization, $clientId, $encodedSecret, $enabled);
|
||||
|
||||
// Reuse buildReadResponse to keep PATCH/GET shapes identical and
|
||||
// guarantee the clientSecret is write-only on every response path.
|
||||
$response->dynamic($this->buildReadResponse($project), static::getResponseModel());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Authentik;
|
||||
|
||||
use Appwrite\Auth\OAuth2\Authentik;
|
||||
use Appwrite\Event\Event as QueueEvent;
|
||||
use Appwrite\Platform\Action;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Base;
|
||||
use Appwrite\SDK\AuthType;
|
||||
use Appwrite\SDK\Method;
|
||||
use Appwrite\SDK\Response as SDKResponse;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\Nullable;
|
||||
use Utopia\Validator\Text;
|
||||
|
||||
class Update extends Base
|
||||
{
|
||||
public static function getProviderId(): string
|
||||
{
|
||||
return 'authentik';
|
||||
}
|
||||
|
||||
public static function getProviderClass(): string
|
||||
{
|
||||
return Authentik::class;
|
||||
}
|
||||
|
||||
public static function getProviderLabel(): string
|
||||
{
|
||||
return 'Authentik';
|
||||
}
|
||||
|
||||
public static function getProviderSDKMethod(): string
|
||||
{
|
||||
return 'updateOAuth2Authentik';
|
||||
}
|
||||
|
||||
public static function getResponseModel(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_AUTHENTIK;
|
||||
}
|
||||
|
||||
public static function getClientIdName(): string
|
||||
{
|
||||
return 'Client ID';
|
||||
}
|
||||
|
||||
public static function getClientIdExample(): string
|
||||
{
|
||||
return 'dTKOPa0000000000000000000000000000e7G8hv';
|
||||
}
|
||||
|
||||
public static function getClientSecretName(): string
|
||||
{
|
||||
return 'Client Secret';
|
||||
}
|
||||
|
||||
public static function getClientSecretExample(): string
|
||||
{
|
||||
return 'ntQadq000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000Hp5WK';
|
||||
}
|
||||
|
||||
public static function getParameters(): array
|
||||
{
|
||||
return \array_merge(parent::getParameters(), [
|
||||
[
|
||||
'$id' => 'endpoint',
|
||||
'name' => 'Domain',
|
||||
'example' => 'example.authentik.com',
|
||||
'hint' => '',
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$providerId = static::getProviderId();
|
||||
$providerLabel = static::getProviderLabel();
|
||||
|
||||
$this
|
||||
->setHttpMethod(Action::HTTP_REQUEST_METHOD_PATCH)
|
||||
->setHttpPath('/v1/project/oauth2/' . $providerId)
|
||||
->desc('Update project OAuth2 ' . $providerLabel)
|
||||
->groups(['api', 'project'])
|
||||
->label('scope', 'oauth2.write')
|
||||
->label('event', 'oauth2.[providerId].update')
|
||||
->label('audits.event', 'project.oauth2.[providerId].update')
|
||||
->label('audits.resource', 'project.oauth2/{response.$id}')
|
||||
->label('sdk', new Method(
|
||||
namespace: 'project',
|
||||
group: 'oauth2',
|
||||
name: static::getProviderSDKMethod(),
|
||||
description: 'Update the project OAuth2 ' . $providerLabel . ' configuration.',
|
||||
auth: [AuthType::ADMIN, AuthType::KEY],
|
||||
responses: [
|
||||
new SDKResponse(
|
||||
code: Response::STATUS_CODE_OK,
|
||||
model: static::getResponseModel(),
|
||||
)
|
||||
],
|
||||
))
|
||||
->param(static::getClientIdParamName(), null, new Nullable(new Text(256, 0)), static::getClientIdDescription(), optional: true)
|
||||
->param(static::getClientSecretParamName(), null, new Nullable(new Text(512, 0)), static::getClientSecretDescription(), optional: true)
|
||||
->param('endpoint', '', new Text(256, 1), 'Domain of Authentik instance. For example: example.authentik.com', optional: false)
|
||||
->param('enabled', null, new Nullable(new Boolean()), 'OAuth2 sign-in method status. Set to true to enable new session creation. Setting to true will trigger end-to-end credentials validation, and will throw if the credentials are invalid.', true)
|
||||
->inject('response')
|
||||
->inject('dbForPlatform')
|
||||
->inject('project')
|
||||
->inject('authorization')
|
||||
->inject('queueForEvents')
|
||||
->callback($this->handle(...));
|
||||
}
|
||||
|
||||
public function buildReadResponse(Document $project): Document
|
||||
{
|
||||
$providerId = static::getProviderId();
|
||||
$oAuthProviders = $project->getAttribute('oAuthProviders', []);
|
||||
$decoded = $this->decodeStoredSecret($project);
|
||||
|
||||
return new Document([
|
||||
'$id' => $providerId,
|
||||
'enabled' => $oAuthProviders[$providerId . 'Enabled'] ?? false,
|
||||
static::getClientIdParamName() => $oAuthProviders[$providerId . 'Appid'] ?? '',
|
||||
static::getClientSecretParamName() => '',
|
||||
'endpoint' => $decoded['authentikDomain'] ?? '',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom callback used instead of the parent's `action()` because Authentik
|
||||
* takes an additional required `endpoint` parameter. The method is named
|
||||
* differently to avoid an LSP-incompatible override of Base::action().
|
||||
*/
|
||||
public function handle(
|
||||
?string $clientId,
|
||||
?string $clientSecret,
|
||||
string $endpoint,
|
||||
?bool $enabled,
|
||||
Response $response,
|
||||
Database $dbForPlatform,
|
||||
Document $project,
|
||||
Authorization $authorization,
|
||||
QueueEvent $queueForEvents
|
||||
): void {
|
||||
$providerId = static::getProviderId();
|
||||
$queueForEvents->setParam('providerId', $providerId);
|
||||
|
||||
// The secret is stored as JSON `{"clientSecret": "...", "authentikDomain": "..."}`
|
||||
// to match the shape Authentik's OAuth2 adapter expects (getAuthentikDomain()).
|
||||
// The `endpoint` param is required on every call, so it's always written.
|
||||
// `clientSecret` is optional; if omitted, the existing stored secret is preserved.
|
||||
$storedRaw = $project->getAttribute('oAuthProviders', [])[$providerId . 'Secret'] ?? '';
|
||||
$existing = [];
|
||||
if (!empty($storedRaw)) {
|
||||
$existing = \json_decode($storedRaw, true) ?: [];
|
||||
}
|
||||
$encodedSecret = \json_encode([
|
||||
'clientSecret' => $clientSecret ?? ($existing['clientSecret'] ?? ''),
|
||||
'authentikDomain' => $endpoint,
|
||||
]);
|
||||
|
||||
$project = $this->persistCredentials($project, $dbForPlatform, $authorization, $clientId, $encodedSecret, $enabled);
|
||||
|
||||
// Reuse buildReadResponse to keep PATCH/GET shapes identical and
|
||||
// guarantee the clientSecret is write-only on every response path.
|
||||
$response->dynamic($this->buildReadResponse($project), static::getResponseModel());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Autodesk;
|
||||
|
||||
use Appwrite\Auth\OAuth2\Autodesk;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Base;
|
||||
use Appwrite\Utopia\Response;
|
||||
|
||||
class Update extends Base
|
||||
{
|
||||
public static function getProviderId(): string
|
||||
{
|
||||
return 'autodesk';
|
||||
}
|
||||
|
||||
public static function getProviderClass(): string
|
||||
{
|
||||
return Autodesk::class;
|
||||
}
|
||||
|
||||
public static function getProviderLabel(): string
|
||||
{
|
||||
return 'Autodesk';
|
||||
}
|
||||
|
||||
public static function getProviderSDKMethod(): string
|
||||
{
|
||||
return 'updateOAuth2Autodesk';
|
||||
}
|
||||
|
||||
public static function getResponseModel(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_AUTODESK;
|
||||
}
|
||||
|
||||
public static function getClientIdName(): string
|
||||
{
|
||||
return 'Client ID';
|
||||
}
|
||||
|
||||
public static function getClientIdExample(): string
|
||||
{
|
||||
return '5zw90v00000000000000000000kVYXN7';
|
||||
}
|
||||
|
||||
public static function getClientSecretName(): string
|
||||
{
|
||||
return 'Client Secret';
|
||||
}
|
||||
|
||||
public static function getClientSecretExample(): string
|
||||
{
|
||||
return '7I000000000000MW';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,449 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Project\Http\Project\OAuth2;
|
||||
|
||||
use Appwrite\Event\Event as QueueEvent;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Platform\Action;
|
||||
use Appwrite\SDK\AuthType;
|
||||
use Appwrite\SDK\Method;
|
||||
use Appwrite\SDK\Response as SDKResponse;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Platform\Scope\HTTP;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\Nullable;
|
||||
use Utopia\Validator\Text;
|
||||
|
||||
abstract class Base extends Action
|
||||
{
|
||||
use HTTP;
|
||||
|
||||
/**
|
||||
* Provider ID used in paths, database keys and event labels.
|
||||
*
|
||||
* @return string e.g. 'github', 'discord', 'figma'
|
||||
*/
|
||||
abstract public static function getProviderId(): string;
|
||||
|
||||
/**
|
||||
* Provider OAuth2 implementation class. Must implement verifyCredentials().
|
||||
*
|
||||
* @return class-string e.g. Github::class
|
||||
*/
|
||||
abstract public static function getProviderClass(): string;
|
||||
|
||||
/**
|
||||
* Provider display label used in descriptions, SDK method name and action name.
|
||||
*
|
||||
* @return string e.g. 'GitHub', 'Discord', 'Figma'
|
||||
*/
|
||||
abstract public static function getProviderLabel(): string;
|
||||
|
||||
/**
|
||||
* Response model constant for this provider.
|
||||
*
|
||||
* @return string e.g. Response::MODEL_OAUTH2_GITHUB
|
||||
*/
|
||||
abstract public static function getResponseModel(): string;
|
||||
|
||||
/**
|
||||
* Description of the clientId param, auto-built from
|
||||
* {@see getClientIdName()}, {@see getClientIdExample()} and
|
||||
* {@see getClientIdHint()}. Returns an empty string when the name is
|
||||
* empty (e.g. providers like Apple that don't expose a single clientId
|
||||
* description but still need to bypass this default).
|
||||
*/
|
||||
public static function getClientIdDescription(): string
|
||||
{
|
||||
return self::buildParamDescription(
|
||||
static::getClientIdName(),
|
||||
static::getClientIdExample(),
|
||||
static::getClientIdHint()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Description of the clientSecret param, auto-built from
|
||||
* {@see getClientSecretName()}, {@see getClientSecretExample()} and
|
||||
* {@see getClientSecretHint()}. Returns an empty string when the name
|
||||
* is empty (e.g. Apple, which uses keyId/teamId/p8File instead).
|
||||
*/
|
||||
public static function getClientSecretDescription(): string
|
||||
{
|
||||
return self::buildParamDescription(
|
||||
static::getClientSecretName(),
|
||||
static::getClientSecretExample(),
|
||||
static::getClientSecretHint()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a parameter description as
|
||||
* "'<name>' of <providerLabel> OAuth2 app. For example: <example>[. <hint>]".
|
||||
* Returns an empty string when the name is empty.
|
||||
*/
|
||||
private static function buildParamDescription(string $name, string $example, string $hint): string
|
||||
{
|
||||
if ($name === '') {
|
||||
return '';
|
||||
}
|
||||
|
||||
$description = '\'' . $name . '\' of ' . static::getProviderLabel() . ' OAuth2 app. For example: ' . $example;
|
||||
if ($hint !== '') {
|
||||
$description .= '. ' . $hint;
|
||||
}
|
||||
|
||||
return $description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verbose, user-facing name of the clientId param. Includes alternate
|
||||
* names when the provider exposes more than one (e.g. "Client ID or App
|
||||
* ID", "Application ID (also known as Client ID)").
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract public static function getClientIdName(): string;
|
||||
|
||||
/**
|
||||
* Example value of the clientId param. Used to build the public OAuth2
|
||||
* providers metadata response.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract public static function getClientIdExample(): string;
|
||||
|
||||
/**
|
||||
* Optional hint for the clientId param. Typically used to call out a
|
||||
* common wrong value (e.g. "Example of wrong value: 370006"). Defaults
|
||||
* to an empty string.
|
||||
*/
|
||||
public static function getClientIdHint(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Verbose, user-facing name of the clientSecret param. Returns an empty
|
||||
* string for providers that don't have a single clientSecret param
|
||||
* (e.g. Apple uses keyId/teamId/p8File instead).
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract public static function getClientSecretName(): string;
|
||||
|
||||
/**
|
||||
* Example value of the clientSecret param. Returns an empty string for
|
||||
* providers without a clientSecret param.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract public static function getClientSecretExample(): string;
|
||||
|
||||
/**
|
||||
* Optional hint for the clientSecret param. Defaults to an empty string.
|
||||
*/
|
||||
public static function getClientSecretHint(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Public-facing parameter metadata for this provider. Used by the public
|
||||
* console OAuth2 providers endpoint to describe the form fields a project
|
||||
* owner must fill in to configure the provider.
|
||||
*
|
||||
* Default shape: clientId + clientSecret. Providers that take additional
|
||||
* fields (Apple, Auth0, Authentik, Gitlab, Microsoft, Oidc, Okta)
|
||||
* override this method to add or replace entries. Each parameter is an
|
||||
* associative array with keys `$id`, `name`, `example`, `hint`.
|
||||
*
|
||||
* @return array<int, array<string, string>>
|
||||
*/
|
||||
public static function getParameters(): array
|
||||
{
|
||||
$parameters = [];
|
||||
|
||||
$clientIdName = static::getClientIdName();
|
||||
if ($clientIdName !== '') {
|
||||
$parameters[] = [
|
||||
'$id' => static::getClientIdParamName(),
|
||||
'name' => $clientIdName,
|
||||
'example' => static::getClientIdExample(),
|
||||
'hint' => static::getClientIdHint(),
|
||||
];
|
||||
}
|
||||
|
||||
$clientSecretName = static::getClientSecretName();
|
||||
if ($clientSecretName !== '') {
|
||||
$parameters[] = [
|
||||
'$id' => static::getClientSecretParamName(),
|
||||
'name' => $clientSecretName,
|
||||
'example' => static::getClientSecretExample(),
|
||||
'hint' => static::getClientSecretHint(),
|
||||
];
|
||||
}
|
||||
|
||||
return $parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Public-facing name of the clientId param. Some providers use a different
|
||||
* terminology (e.g. Dropbox calls it "App key"), so the param name and the
|
||||
* corresponding response field can be customized by overriding this method.
|
||||
*
|
||||
* @return string e.g. 'clientId' (default), 'appKey'
|
||||
*/
|
||||
public static function getClientIdParamName(): string
|
||||
{
|
||||
return 'clientId';
|
||||
}
|
||||
|
||||
/**
|
||||
* Public-facing name of the clientSecret param. Some providers use a
|
||||
* different terminology (e.g. Dropbox calls it "App secret"), so the param
|
||||
* name and the corresponding response field can be customized by
|
||||
* overriding this method.
|
||||
*
|
||||
* @return string e.g. 'clientSecret' (default), 'appSecret'
|
||||
*/
|
||||
public static function getClientSecretParamName(): string
|
||||
{
|
||||
return 'clientSecret';
|
||||
}
|
||||
|
||||
/**
|
||||
* SDK method name exposed to clients.
|
||||
*
|
||||
* @return string e.g. 'updateOAuth2GitHub'
|
||||
*/
|
||||
abstract public static function getProviderSDKMethod(): string;
|
||||
|
||||
public static function getName()
|
||||
{
|
||||
return 'updateProjectOAuth2' . static::getProviderLabel();
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$providerId = static::getProviderId();
|
||||
$providerLabel = static::getProviderLabel();
|
||||
|
||||
$this
|
||||
->setHttpMethod(Action::HTTP_REQUEST_METHOD_PATCH)
|
||||
->setHttpPath('/v1/project/oauth2/' . $providerId)
|
||||
->desc('Update project OAuth2 ' . $providerLabel)
|
||||
->groups(['api', 'project'])
|
||||
->label('scope', 'oauth2.write')
|
||||
->label('event', 'oauth2.[providerId].update')
|
||||
->label('audits.event', 'project.oauth2.[providerId].update')
|
||||
->label('audits.resource', 'project.oauth2/{response.$id}')
|
||||
->label('sdk', new Method(
|
||||
namespace: 'project',
|
||||
group: 'oauth2',
|
||||
name: static::getProviderSDKMethod(),
|
||||
description: 'Update the project OAuth2 ' . $providerLabel . ' configuration.',
|
||||
auth: [AuthType::ADMIN, AuthType::KEY],
|
||||
responses: [
|
||||
new SDKResponse(
|
||||
code: Response::STATUS_CODE_OK,
|
||||
model: static::getResponseModel(),
|
||||
)
|
||||
],
|
||||
))
|
||||
->param(static::getClientIdParamName(), null, new Nullable(new Text(256, 0)), static::getClientIdDescription(), optional: true)
|
||||
->param(static::getClientSecretParamName(), null, new Nullable(new Text(512, 0)), static::getClientSecretDescription(), optional: true)
|
||||
->param('enabled', null, new Nullable(new Boolean()), 'OAuth2 sign-in method status. Set to true to enable new session creation. Setting to true will trigger end-to-end credentials validation, and will throw if the credentials are invalid.', true)
|
||||
->inject('response')
|
||||
->inject('dbForPlatform')
|
||||
->inject('project')
|
||||
->inject('authorization')
|
||||
->inject('queueForEvents')
|
||||
->callback($this->action(...));
|
||||
}
|
||||
|
||||
/**
|
||||
* Registry of provider ID -> Update action class. Mirrors the OAuth2
|
||||
* actions registered in Project\Services\Http. Used by the Get and XList
|
||||
* read endpoints to dispatch per-provider response shaping.
|
||||
*
|
||||
* @return array<string, class-string<Base>>
|
||||
*/
|
||||
public static function getProviderActions(): array
|
||||
{
|
||||
return [
|
||||
'github' => GitHub\Update::class,
|
||||
'discord' => Discord\Update::class,
|
||||
'figma' => Figma\Update::class,
|
||||
'dropbox' => Dropbox\Update::class,
|
||||
'dailymotion' => Dailymotion\Update::class,
|
||||
'bitbucket' => Bitbucket\Update::class,
|
||||
'bitly' => Bitly\Update::class,
|
||||
'box' => Box\Update::class,
|
||||
'autodesk' => Autodesk\Update::class,
|
||||
'google' => Google\Update::class,
|
||||
'zoom' => Zoom\Update::class,
|
||||
'zoho' => Zoho\Update::class,
|
||||
'yandex' => Yandex\Update::class,
|
||||
'x' => X\Update::class,
|
||||
'wordpress' => WordPress\Update::class,
|
||||
'twitch' => Twitch\Update::class,
|
||||
'stripe' => Stripe\Update::class,
|
||||
'spotify' => Spotify\Update::class,
|
||||
'slack' => Slack\Update::class,
|
||||
'podio' => Podio\Update::class,
|
||||
'notion' => Notion\Update::class,
|
||||
'salesforce' => Salesforce\Update::class,
|
||||
'yahoo' => Yahoo\Update::class,
|
||||
'linkedin' => Linkedin\Update::class,
|
||||
'disqus' => Disqus\Update::class,
|
||||
'amazon' => Amazon\Update::class,
|
||||
'etsy' => Etsy\Update::class,
|
||||
'facebook' => Facebook\Update::class,
|
||||
'tradeshift' => Tradeshift\Update::class,
|
||||
'tradeshiftBox' => TradeshiftSandbox\Update::class,
|
||||
'paypal' => Paypal\Update::class,
|
||||
'paypalSandbox' => PaypalSandbox\Update::class,
|
||||
'gitlab' => Gitlab\Update::class,
|
||||
'authentik' => Authentik\Update::class,
|
||||
'auth0' => Auth0\Update::class,
|
||||
'fusionauth' => FusionAuth\Update::class,
|
||||
'keycloak' => Keycloak\Update::class,
|
||||
'oidc' => Oidc\Update::class,
|
||||
'okta' => Okta\Update::class,
|
||||
'kick' => Kick\Update::class,
|
||||
'apple' => Apple\Update::class,
|
||||
'microsoft' => Microsoft\Update::class,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the read-only response document for this provider, with credential
|
||||
* fields zeroed out (write-only). Default implementation handles providers
|
||||
* that store a plain client ID + client secret. Special providers (Apple,
|
||||
* Gitlab, Auth0, Authentik, Oidc, Okta) override to expose their
|
||||
* non-secret extras (endpoint, domain, discovery URLs, ...) decoded from
|
||||
* the JSON-encoded secret blob.
|
||||
*/
|
||||
public function buildReadResponse(Document $project): Document
|
||||
{
|
||||
$providerId = static::getProviderId();
|
||||
$oAuthProviders = $project->getAttribute('oAuthProviders', []);
|
||||
|
||||
return new Document([
|
||||
'$id' => $providerId,
|
||||
'enabled' => $oAuthProviders[$providerId . 'Enabled'] ?? false,
|
||||
static::getClientIdParamName() => $oAuthProviders[$providerId . 'Appid'] ?? '',
|
||||
static::getClientSecretParamName() => '',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode the JSON-encoded secret blob stored under `{providerId}Secret`.
|
||||
* Returns an empty array when the value is empty or not valid JSON.
|
||||
*/
|
||||
protected function decodeStoredSecret(Document $project): array
|
||||
{
|
||||
$providerId = static::getProviderId();
|
||||
$stored = $project->getAttribute('oAuthProviders', [])[$providerId . 'Secret'] ?? '';
|
||||
|
||||
if (empty($stored)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$decoded = \json_decode($stored, true);
|
||||
return \is_array($decoded) ? $decoded : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the provided credential changes to the project's oAuthProviders map,
|
||||
* run the optional credential verification hook, persist the project, and
|
||||
* return the updated project document.
|
||||
*
|
||||
* Providers that need to serialize multiple values into a single secret
|
||||
* (e.g. GitLab, which stores `{clientSecret, endpoint}` as JSON) should
|
||||
* encode those values into `$clientSecret` before calling this method.
|
||||
*/
|
||||
protected function persistCredentials(
|
||||
Document $project,
|
||||
Database $dbForPlatform,
|
||||
Authorization $authorization,
|
||||
?string $clientId,
|
||||
?string $clientSecret,
|
||||
?bool $enabled
|
||||
): Document {
|
||||
$providerId = static::getProviderId();
|
||||
if (!(\in_array($providerId, \array_keys(Config::getParam('oAuthProviders'))))) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Provider ' . $providerId . ' is not supported by server configuration.');
|
||||
}
|
||||
|
||||
$oAuthProviders = $project->getAttribute('oAuthProviders', []);
|
||||
|
||||
$appIdKey = $providerId . 'Appid';
|
||||
$appSecretKey = $providerId . 'Secret';
|
||||
$enabledKey = $providerId . 'Enabled';
|
||||
|
||||
if (!\is_null($clientId)) {
|
||||
$oAuthProviders[$appIdKey] = $clientId;
|
||||
}
|
||||
|
||||
if (!\is_null($clientSecret)) {
|
||||
$oAuthProviders[$appSecretKey] = $clientSecret;
|
||||
}
|
||||
|
||||
if (!\is_null($enabled)) {
|
||||
$oAuthProviders[$enabledKey] = $enabled;
|
||||
}
|
||||
|
||||
if ($enabled === true || \is_null($enabled)) {
|
||||
try {
|
||||
if (empty($oAuthProviders[$appIdKey]) || empty($oAuthProviders[$appSecretKey])) {
|
||||
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'Client ID and Client Secret are required when enabling OAuth2 provider.');
|
||||
}
|
||||
|
||||
$providerClass = static::getProviderClass();
|
||||
$providerInstance = new $providerClass(appId: $oAuthProviders[$appIdKey], appSecret: $oAuthProviders[$appSecretKey], callback: '', state: [], scopes: []);
|
||||
|
||||
// E2E integration check
|
||||
if (\method_exists($providerInstance, 'verifyCredentials')) {
|
||||
$providerInstance->verifyCredentials();
|
||||
}
|
||||
|
||||
$oAuthProviders[$enabledKey] = true;
|
||||
} catch (\Throwable $err) {
|
||||
if ($enabled === true) {
|
||||
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'Could not enable OAuth2 provider: ' . $err->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$updates = new Document([
|
||||
'oAuthProviders' => $oAuthProviders
|
||||
]);
|
||||
|
||||
return $authorization->skip(fn () => $dbForPlatform->updateDocument('projects', $project->getId(), $updates));
|
||||
}
|
||||
|
||||
public function action(
|
||||
?string $clientId,
|
||||
?string $clientSecret,
|
||||
?bool $enabled,
|
||||
Response $response,
|
||||
Database $dbForPlatform,
|
||||
Document $project,
|
||||
Authorization $authorization,
|
||||
QueueEvent $queueForEvents
|
||||
): void {
|
||||
$project = $this->persistCredentials($project, $dbForPlatform, $authorization, $clientId, $clientSecret, $enabled);
|
||||
|
||||
$queueForEvents->setParam('providerId', static::getProviderId());
|
||||
|
||||
// Reuse buildReadResponse to keep PATCH/GET shapes identical and
|
||||
// guarantee the clientSecret is write-only on every response path.
|
||||
$response->dynamic($this->buildReadResponse($project), static::getResponseModel());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Bitbucket;
|
||||
|
||||
use Appwrite\Auth\OAuth2\Bitbucket;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Base;
|
||||
use Appwrite\Utopia\Response;
|
||||
|
||||
class Update extends Base
|
||||
{
|
||||
public static function getProviderId(): string
|
||||
{
|
||||
return 'bitbucket';
|
||||
}
|
||||
|
||||
public static function getProviderClass(): string
|
||||
{
|
||||
return Bitbucket::class;
|
||||
}
|
||||
|
||||
public static function getProviderLabel(): string
|
||||
{
|
||||
return 'Bitbucket';
|
||||
}
|
||||
|
||||
public static function getProviderSDKMethod(): string
|
||||
{
|
||||
return 'updateOAuth2Bitbucket';
|
||||
}
|
||||
|
||||
public static function getResponseModel(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_BITBUCKET;
|
||||
}
|
||||
|
||||
public static function getClientIdParamName(): string
|
||||
{
|
||||
return 'key';
|
||||
}
|
||||
|
||||
public static function getClientSecretParamName(): string
|
||||
{
|
||||
return 'secret';
|
||||
}
|
||||
|
||||
public static function getClientIdName(): string
|
||||
{
|
||||
return 'Key';
|
||||
}
|
||||
|
||||
public static function getClientIdExample(): string
|
||||
{
|
||||
return 'Knt70000000000ByRc';
|
||||
}
|
||||
|
||||
public static function getClientSecretName(): string
|
||||
{
|
||||
return 'Secret';
|
||||
}
|
||||
|
||||
public static function getClientSecretExample(): string
|
||||
{
|
||||
return 'NMfLZJ00000000000000000000TLQdDx';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Bitly;
|
||||
|
||||
use Appwrite\Auth\OAuth2\Bitly;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Base;
|
||||
use Appwrite\Utopia\Response;
|
||||
|
||||
class Update extends Base
|
||||
{
|
||||
public static function getProviderId(): string
|
||||
{
|
||||
return 'bitly';
|
||||
}
|
||||
|
||||
public static function getProviderClass(): string
|
||||
{
|
||||
return Bitly::class;
|
||||
}
|
||||
|
||||
public static function getProviderLabel(): string
|
||||
{
|
||||
return 'Bitly';
|
||||
}
|
||||
|
||||
public static function getProviderSDKMethod(): string
|
||||
{
|
||||
return 'updateOAuth2Bitly';
|
||||
}
|
||||
|
||||
public static function getResponseModel(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_BITLY;
|
||||
}
|
||||
|
||||
public static function getClientIdName(): string
|
||||
{
|
||||
return 'Client ID';
|
||||
}
|
||||
|
||||
public static function getClientIdExample(): string
|
||||
{
|
||||
return 'd95151000000000000000000000000000067af9b';
|
||||
}
|
||||
|
||||
public static function getClientSecretName(): string
|
||||
{
|
||||
return 'Client Secret';
|
||||
}
|
||||
|
||||
public static function getClientSecretExample(): string
|
||||
{
|
||||
return 'a13e250000000000000000000000000000d73095';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Box;
|
||||
|
||||
use Appwrite\Auth\OAuth2\Box;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Base;
|
||||
use Appwrite\Utopia\Response;
|
||||
|
||||
class Update extends Base
|
||||
{
|
||||
public static function getProviderId(): string
|
||||
{
|
||||
return 'box';
|
||||
}
|
||||
|
||||
public static function getProviderClass(): string
|
||||
{
|
||||
return Box::class;
|
||||
}
|
||||
|
||||
public static function getProviderLabel(): string
|
||||
{
|
||||
return 'Box';
|
||||
}
|
||||
|
||||
public static function getProviderSDKMethod(): string
|
||||
{
|
||||
return 'updateOAuth2Box';
|
||||
}
|
||||
|
||||
public static function getResponseModel(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_BOX;
|
||||
}
|
||||
|
||||
public static function getClientIdName(): string
|
||||
{
|
||||
return 'Client ID';
|
||||
}
|
||||
|
||||
public static function getClientIdExample(): string
|
||||
{
|
||||
return 'deglcs00000000000000000000x2og6y';
|
||||
}
|
||||
|
||||
public static function getClientSecretName(): string
|
||||
{
|
||||
return 'Client Secret';
|
||||
}
|
||||
|
||||
public static function getClientSecretExample(): string
|
||||
{
|
||||
return 'OKM1f100000000000000000000eshEif';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Dailymotion;
|
||||
|
||||
use Appwrite\Auth\OAuth2\Dailymotion;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Base;
|
||||
use Appwrite\Utopia\Response;
|
||||
|
||||
class Update extends Base
|
||||
{
|
||||
public static function getProviderId(): string
|
||||
{
|
||||
return 'dailymotion';
|
||||
}
|
||||
|
||||
public static function getProviderClass(): string
|
||||
{
|
||||
return Dailymotion::class;
|
||||
}
|
||||
|
||||
public static function getProviderLabel(): string
|
||||
{
|
||||
return 'Dailymotion';
|
||||
}
|
||||
|
||||
public static function getProviderSDKMethod(): string
|
||||
{
|
||||
return 'updateOAuth2Dailymotion';
|
||||
}
|
||||
|
||||
public static function getResponseModel(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_DAILYMOTION;
|
||||
}
|
||||
|
||||
public static function getClientIdParamName(): string
|
||||
{
|
||||
return 'apiKey';
|
||||
}
|
||||
|
||||
public static function getClientSecretParamName(): string
|
||||
{
|
||||
return 'apiSecret';
|
||||
}
|
||||
|
||||
public static function getClientIdName(): string
|
||||
{
|
||||
return 'API Key';
|
||||
}
|
||||
|
||||
public static function getClientIdExample(): string
|
||||
{
|
||||
return '07a9000000000000067f';
|
||||
}
|
||||
|
||||
public static function getClientSecretName(): string
|
||||
{
|
||||
return 'API Secret';
|
||||
}
|
||||
|
||||
public static function getClientSecretExample(): string
|
||||
{
|
||||
return 'a399a90000000000000000000000000000d90639';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Discord;
|
||||
|
||||
use Appwrite\Auth\OAuth2\Discord;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Base;
|
||||
use Appwrite\Utopia\Response;
|
||||
|
||||
class Update extends Base
|
||||
{
|
||||
public static function getProviderId(): string
|
||||
{
|
||||
return 'discord';
|
||||
}
|
||||
|
||||
public static function getProviderClass(): string
|
||||
{
|
||||
return Discord::class;
|
||||
}
|
||||
|
||||
public static function getProviderLabel(): string
|
||||
{
|
||||
return 'Discord';
|
||||
}
|
||||
|
||||
public static function getProviderSDKMethod(): string
|
||||
{
|
||||
return 'updateOAuth2Discord';
|
||||
}
|
||||
|
||||
public static function getResponseModel(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_DISCORD;
|
||||
}
|
||||
|
||||
public static function getClientIdName(): string
|
||||
{
|
||||
return 'Client ID';
|
||||
}
|
||||
|
||||
public static function getClientIdExample(): string
|
||||
{
|
||||
return '950722000000343754';
|
||||
}
|
||||
|
||||
public static function getClientSecretName(): string
|
||||
{
|
||||
return 'Client Secret';
|
||||
}
|
||||
|
||||
public static function getClientSecretExample(): string
|
||||
{
|
||||
return 'YmPXnM000000000000000000002zFg5D';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Disqus;
|
||||
|
||||
use Appwrite\Auth\OAuth2\Disqus;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Base;
|
||||
use Appwrite\Utopia\Response;
|
||||
|
||||
class Update extends Base
|
||||
{
|
||||
public static function getProviderId(): string
|
||||
{
|
||||
return 'disqus';
|
||||
}
|
||||
|
||||
public static function getProviderClass(): string
|
||||
{
|
||||
return Disqus::class;
|
||||
}
|
||||
|
||||
public static function getProviderLabel(): string
|
||||
{
|
||||
return 'Disqus';
|
||||
}
|
||||
|
||||
public static function getProviderSDKMethod(): string
|
||||
{
|
||||
return 'updateOAuth2Disqus';
|
||||
}
|
||||
|
||||
public static function getResponseModel(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_DISQUS;
|
||||
}
|
||||
|
||||
public static function getClientIdParamName(): string
|
||||
{
|
||||
return 'publicKey';
|
||||
}
|
||||
|
||||
public static function getClientSecretParamName(): string
|
||||
{
|
||||
return 'secretKey';
|
||||
}
|
||||
|
||||
public static function getClientIdName(): string
|
||||
{
|
||||
return 'Public Key, also known as API Key';
|
||||
}
|
||||
|
||||
public static function getClientIdExample(): string
|
||||
{
|
||||
return 'cgegH70000000000000000000000000000000000000000000000000000Hr1nYX';
|
||||
}
|
||||
|
||||
public static function getClientSecretName(): string
|
||||
{
|
||||
return 'Secret Key, also known as API Secret';
|
||||
}
|
||||
|
||||
public static function getClientSecretExample(): string
|
||||
{
|
||||
return 'W7Bykj00000000000000000000000000000000000000000000000000003o43w9';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Dropbox;
|
||||
|
||||
use Appwrite\Auth\OAuth2\Dropbox;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Base;
|
||||
use Appwrite\Utopia\Response;
|
||||
|
||||
class Update extends Base
|
||||
{
|
||||
public static function getProviderId(): string
|
||||
{
|
||||
return 'dropbox';
|
||||
}
|
||||
|
||||
public static function getProviderClass(): string
|
||||
{
|
||||
return Dropbox::class;
|
||||
}
|
||||
|
||||
public static function getProviderLabel(): string
|
||||
{
|
||||
return 'Dropbox';
|
||||
}
|
||||
|
||||
public static function getProviderSDKMethod(): string
|
||||
{
|
||||
return 'updateOAuth2Dropbox';
|
||||
}
|
||||
|
||||
public static function getResponseModel(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_DROPBOX;
|
||||
}
|
||||
|
||||
public static function getClientIdParamName(): string
|
||||
{
|
||||
return 'appKey';
|
||||
}
|
||||
|
||||
public static function getClientSecretParamName(): string
|
||||
{
|
||||
return 'appSecret';
|
||||
}
|
||||
|
||||
public static function getClientIdName(): string
|
||||
{
|
||||
return 'App Key';
|
||||
}
|
||||
|
||||
public static function getClientIdExample(): string
|
||||
{
|
||||
return 'jl000000000009t';
|
||||
}
|
||||
|
||||
public static function getClientSecretName(): string
|
||||
{
|
||||
return 'App Secret';
|
||||
}
|
||||
|
||||
public static function getClientSecretExample(): string
|
||||
{
|
||||
return 'g200000000000vw';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Etsy;
|
||||
|
||||
use Appwrite\Auth\OAuth2\Etsy;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Base;
|
||||
use Appwrite\Utopia\Response;
|
||||
|
||||
class Update extends Base
|
||||
{
|
||||
public static function getProviderId(): string
|
||||
{
|
||||
return 'etsy';
|
||||
}
|
||||
|
||||
public static function getProviderClass(): string
|
||||
{
|
||||
return Etsy::class;
|
||||
}
|
||||
|
||||
public static function getProviderLabel(): string
|
||||
{
|
||||
return 'Etsy';
|
||||
}
|
||||
|
||||
public static function getProviderSDKMethod(): string
|
||||
{
|
||||
return 'updateOAuth2Etsy';
|
||||
}
|
||||
|
||||
public static function getResponseModel(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_ETSY;
|
||||
}
|
||||
|
||||
public static function getClientIdParamName(): string
|
||||
{
|
||||
return 'keyString';
|
||||
}
|
||||
|
||||
public static function getClientSecretParamName(): string
|
||||
{
|
||||
return 'sharedSecret';
|
||||
}
|
||||
|
||||
public static function getClientIdName(): string
|
||||
{
|
||||
return 'Keystring';
|
||||
}
|
||||
|
||||
public static function getClientIdExample(): string
|
||||
{
|
||||
return 'nsgzxh0000000000008j85a2';
|
||||
}
|
||||
|
||||
public static function getClientSecretName(): string
|
||||
{
|
||||
return 'Shared Secret';
|
||||
}
|
||||
|
||||
public static function getClientSecretExample(): string
|
||||
{
|
||||
return 'tp000000ru';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Facebook;
|
||||
|
||||
use Appwrite\Auth\OAuth2\Facebook;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Base;
|
||||
use Appwrite\Utopia\Response;
|
||||
|
||||
class Update extends Base
|
||||
{
|
||||
public static function getProviderId(): string
|
||||
{
|
||||
return 'facebook';
|
||||
}
|
||||
|
||||
public static function getProviderClass(): string
|
||||
{
|
||||
return Facebook::class;
|
||||
}
|
||||
|
||||
public static function getProviderLabel(): string
|
||||
{
|
||||
return 'Facebook';
|
||||
}
|
||||
|
||||
public static function getProviderSDKMethod(): string
|
||||
{
|
||||
return 'updateOAuth2Facebook';
|
||||
}
|
||||
|
||||
public static function getResponseModel(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_FACEBOOK;
|
||||
}
|
||||
|
||||
public static function getClientIdParamName(): string
|
||||
{
|
||||
return 'appId';
|
||||
}
|
||||
|
||||
public static function getClientSecretParamName(): string
|
||||
{
|
||||
return 'appSecret';
|
||||
}
|
||||
|
||||
public static function getClientIdName(): string
|
||||
{
|
||||
return 'App ID';
|
||||
}
|
||||
|
||||
public static function getClientIdExample(): string
|
||||
{
|
||||
return '260600000007694';
|
||||
}
|
||||
|
||||
public static function getClientSecretName(): string
|
||||
{
|
||||
return 'App Secret';
|
||||
}
|
||||
|
||||
public static function getClientSecretExample(): string
|
||||
{
|
||||
return '2d0b2800000000000000000000d38af4';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Figma;
|
||||
|
||||
use Appwrite\Auth\OAuth2\Figma;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Base;
|
||||
use Appwrite\Utopia\Response;
|
||||
|
||||
class Update extends Base
|
||||
{
|
||||
public static function getProviderId(): string
|
||||
{
|
||||
return 'figma';
|
||||
}
|
||||
|
||||
public static function getProviderClass(): string
|
||||
{
|
||||
return Figma::class;
|
||||
}
|
||||
|
||||
public static function getProviderLabel(): string
|
||||
{
|
||||
return 'Figma';
|
||||
}
|
||||
|
||||
public static function getProviderSDKMethod(): string
|
||||
{
|
||||
return 'updateOAuth2Figma';
|
||||
}
|
||||
|
||||
public static function getResponseModel(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_FIGMA;
|
||||
}
|
||||
|
||||
public static function getClientIdName(): string
|
||||
{
|
||||
return 'Client ID';
|
||||
}
|
||||
|
||||
public static function getClientIdExample(): string
|
||||
{
|
||||
return 'byay5H0000000000VtiI40';
|
||||
}
|
||||
|
||||
public static function getClientSecretName(): string
|
||||
{
|
||||
return 'Client Secret';
|
||||
}
|
||||
|
||||
public static function getClientSecretExample(): string
|
||||
{
|
||||
return 'yEpOYn0000000000000000004iIsU5';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Project\Http\Project\OAuth2\FusionAuth;
|
||||
|
||||
use Appwrite\Auth\OAuth2\FusionAuth;
|
||||
use Appwrite\Event\Event as QueueEvent;
|
||||
use Appwrite\Platform\Action;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Base;
|
||||
use Appwrite\SDK\AuthType;
|
||||
use Appwrite\SDK\Method;
|
||||
use Appwrite\SDK\Response as SDKResponse;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\Nullable;
|
||||
use Utopia\Validator\Text;
|
||||
|
||||
class Update extends Base
|
||||
{
|
||||
public static function getProviderId(): string
|
||||
{
|
||||
return 'fusionauth';
|
||||
}
|
||||
|
||||
public static function getProviderClass(): string
|
||||
{
|
||||
return FusionAuth::class;
|
||||
}
|
||||
|
||||
public static function getProviderLabel(): string
|
||||
{
|
||||
return 'FusionAuth';
|
||||
}
|
||||
|
||||
public static function getProviderSDKMethod(): string
|
||||
{
|
||||
return 'updateOAuth2FusionAuth';
|
||||
}
|
||||
|
||||
public static function getResponseModel(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_FUSIONAUTH;
|
||||
}
|
||||
|
||||
public static function getClientIdName(): string
|
||||
{
|
||||
return 'Client ID';
|
||||
}
|
||||
|
||||
public static function getClientIdExample(): string
|
||||
{
|
||||
return 'b2222c00-0000-0000-0000-000000862097';
|
||||
}
|
||||
|
||||
public static function getClientSecretName(): string
|
||||
{
|
||||
return 'Client Secret';
|
||||
}
|
||||
|
||||
public static function getClientSecretExample(): string
|
||||
{
|
||||
return 'Jx4s0C0000000000000000000000000000000wGqLsc';
|
||||
}
|
||||
|
||||
public static function getParameters(): array
|
||||
{
|
||||
return \array_merge(parent::getParameters(), [
|
||||
[
|
||||
'$id' => 'endpoint',
|
||||
'name' => 'Domain',
|
||||
'example' => 'example.fusionauth.io',
|
||||
'hint' => '',
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$providerId = static::getProviderId();
|
||||
$providerLabel = static::getProviderLabel();
|
||||
|
||||
$this
|
||||
->setHttpMethod(Action::HTTP_REQUEST_METHOD_PATCH)
|
||||
->setHttpPath('/v1/project/oauth2/' . $providerId)
|
||||
->desc('Update project OAuth2 ' . $providerLabel)
|
||||
->groups(['api', 'project'])
|
||||
->label('scope', 'oauth2.write')
|
||||
->label('event', 'oauth2.[providerId].update')
|
||||
->label('audits.event', 'project.oauth2.[providerId].update')
|
||||
->label('audits.resource', 'project.oauth2/{response.$id}')
|
||||
->label('sdk', new Method(
|
||||
namespace: 'project',
|
||||
group: 'oauth2',
|
||||
name: static::getProviderSDKMethod(),
|
||||
description: 'Update the project OAuth2 ' . $providerLabel . ' configuration.',
|
||||
auth: [AuthType::ADMIN, AuthType::KEY],
|
||||
responses: [
|
||||
new SDKResponse(
|
||||
code: Response::STATUS_CODE_OK,
|
||||
model: static::getResponseModel(),
|
||||
)
|
||||
],
|
||||
))
|
||||
->param(static::getClientIdParamName(), null, new Nullable(new Text(256, 0)), static::getClientIdDescription(), optional: true)
|
||||
->param(static::getClientSecretParamName(), null, new Nullable(new Text(512, 0)), static::getClientSecretDescription(), optional: true)
|
||||
->param('endpoint', '', new Text(256, 1), 'Domain of FusionAuth instance. For example: example.fusionauth.io', optional: false)
|
||||
->param('enabled', null, new Nullable(new Boolean()), 'OAuth2 sign-in method status. Set to true to enable new session creation. Setting to true will trigger end-to-end credentials validation, and will throw if the credentials are invalid.', true)
|
||||
->inject('response')
|
||||
->inject('dbForPlatform')
|
||||
->inject('project')
|
||||
->inject('authorization')
|
||||
->inject('queueForEvents')
|
||||
->callback($this->handle(...));
|
||||
}
|
||||
|
||||
public function buildReadResponse(Document $project): Document
|
||||
{
|
||||
$providerId = static::getProviderId();
|
||||
$oAuthProviders = $project->getAttribute('oAuthProviders', []);
|
||||
$decoded = $this->decodeStoredSecret($project);
|
||||
|
||||
return new Document([
|
||||
'$id' => $providerId,
|
||||
'enabled' => $oAuthProviders[$providerId . 'Enabled'] ?? false,
|
||||
static::getClientIdParamName() => $oAuthProviders[$providerId . 'Appid'] ?? '',
|
||||
static::getClientSecretParamName() => '',
|
||||
'endpoint' => $decoded['fusionAuthDomain'] ?? '',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom callback used instead of the parent's `action()` because FusionAuth
|
||||
* takes an additional required `endpoint` parameter. The method is named
|
||||
* differently to avoid an LSP-incompatible override of Base::action().
|
||||
*/
|
||||
public function handle(
|
||||
?string $clientId,
|
||||
?string $clientSecret,
|
||||
string $endpoint,
|
||||
?bool $enabled,
|
||||
Response $response,
|
||||
Database $dbForPlatform,
|
||||
Document $project,
|
||||
Authorization $authorization,
|
||||
QueueEvent $queueForEvents
|
||||
): void {
|
||||
$providerId = static::getProviderId();
|
||||
$queueForEvents->setParam('providerId', $providerId);
|
||||
|
||||
// The secret is stored as JSON `{"clientSecret": "...", "fusionAuthDomain": "..."}`
|
||||
// to match the shape FusionAuth's OAuth2 adapter expects (getFusionAuthDomain()).
|
||||
// The `endpoint` param is required on every call, so it's always written.
|
||||
// `clientSecret` is optional; if omitted, the existing stored secret is preserved.
|
||||
$storedRaw = $project->getAttribute('oAuthProviders', [])[$providerId . 'Secret'] ?? '';
|
||||
$existing = [];
|
||||
if (!empty($storedRaw)) {
|
||||
$existing = \json_decode($storedRaw, true) ?: [];
|
||||
}
|
||||
$encodedSecret = \json_encode([
|
||||
'clientSecret' => $clientSecret ?? ($existing['clientSecret'] ?? ''),
|
||||
'fusionAuthDomain' => $endpoint,
|
||||
]);
|
||||
|
||||
$project = $this->persistCredentials($project, $dbForPlatform, $authorization, $clientId, $encodedSecret, $enabled);
|
||||
|
||||
// Reuse buildReadResponse to keep PATCH/GET shapes identical and
|
||||
// guarantee the clientSecret is write-only on every response path.
|
||||
$response->dynamic($this->buildReadResponse($project), static::getResponseModel());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Project\Http\Project\OAuth2;
|
||||
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\SDK\AuthType;
|
||||
use Appwrite\SDK\Method;
|
||||
use Appwrite\SDK\Response as SDKResponse;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Platform\Action;
|
||||
use Utopia\Platform\Scope\HTTP;
|
||||
use Utopia\Validator\Text;
|
||||
|
||||
class Get extends Action
|
||||
{
|
||||
use HTTP;
|
||||
|
||||
public static function getName()
|
||||
{
|
||||
return 'getProjectOAuth2';
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this
|
||||
->setHttpMethod(Action::HTTP_REQUEST_METHOD_GET)
|
||||
->setHttpPath('/v1/project/oauth2/:provider')
|
||||
->desc('Get project OAuth2 provider')
|
||||
->groups(['api', 'project'])
|
||||
->label('scope', 'oauth2.read')
|
||||
->label('sdk', new Method(
|
||||
namespace: 'project',
|
||||
group: 'oauth2',
|
||||
name: 'getOAuth2Provider',
|
||||
description: <<<EOT
|
||||
Get a single OAuth2 provider configuration. Credential fields (client secret, p8 file, key/team IDs) are write-only and always returned empty.
|
||||
EOT,
|
||||
auth: [AuthType::ADMIN, AuthType::KEY],
|
||||
responses: [
|
||||
new SDKResponse(
|
||||
code: Response::STATUS_CODE_OK,
|
||||
model: [
|
||||
Response::MODEL_OAUTH2_GITHUB,
|
||||
Response::MODEL_OAUTH2_DISCORD,
|
||||
Response::MODEL_OAUTH2_FIGMA,
|
||||
Response::MODEL_OAUTH2_DROPBOX,
|
||||
Response::MODEL_OAUTH2_DAILYMOTION,
|
||||
Response::MODEL_OAUTH2_BITBUCKET,
|
||||
Response::MODEL_OAUTH2_BITLY,
|
||||
Response::MODEL_OAUTH2_BOX,
|
||||
Response::MODEL_OAUTH2_AUTODESK,
|
||||
Response::MODEL_OAUTH2_GOOGLE,
|
||||
Response::MODEL_OAUTH2_ZOOM,
|
||||
Response::MODEL_OAUTH2_ZOHO,
|
||||
Response::MODEL_OAUTH2_YANDEX,
|
||||
Response::MODEL_OAUTH2_X,
|
||||
Response::MODEL_OAUTH2_WORDPRESS,
|
||||
Response::MODEL_OAUTH2_TWITCH,
|
||||
Response::MODEL_OAUTH2_STRIPE,
|
||||
Response::MODEL_OAUTH2_SPOTIFY,
|
||||
Response::MODEL_OAUTH2_SLACK,
|
||||
Response::MODEL_OAUTH2_PODIO,
|
||||
Response::MODEL_OAUTH2_NOTION,
|
||||
Response::MODEL_OAUTH2_SALESFORCE,
|
||||
Response::MODEL_OAUTH2_YAHOO,
|
||||
Response::MODEL_OAUTH2_LINKEDIN,
|
||||
Response::MODEL_OAUTH2_DISQUS,
|
||||
Response::MODEL_OAUTH2_AMAZON,
|
||||
Response::MODEL_OAUTH2_ETSY,
|
||||
Response::MODEL_OAUTH2_FACEBOOK,
|
||||
Response::MODEL_OAUTH2_TRADESHIFT,
|
||||
Response::MODEL_OAUTH2_PAYPAL,
|
||||
Response::MODEL_OAUTH2_GITLAB,
|
||||
Response::MODEL_OAUTH2_AUTHENTIK,
|
||||
Response::MODEL_OAUTH2_AUTH0,
|
||||
Response::MODEL_OAUTH2_FUSIONAUTH,
|
||||
Response::MODEL_OAUTH2_KEYCLOAK,
|
||||
Response::MODEL_OAUTH2_OIDC,
|
||||
Response::MODEL_OAUTH2_APPLE,
|
||||
Response::MODEL_OAUTH2_OKTA,
|
||||
Response::MODEL_OAUTH2_KICK,
|
||||
Response::MODEL_OAUTH2_MICROSOFT,
|
||||
],
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('provider', '', new Text(128), 'OAuth2 provider key. For example: github, google, apple.')
|
||||
->inject('response')
|
||||
->inject('project')
|
||||
->callback($this->action(...));
|
||||
}
|
||||
|
||||
public function action(
|
||||
string $provider,
|
||||
Response $response,
|
||||
Document $project,
|
||||
): void {
|
||||
$providers = Config::getParam('oAuthProviders', []);
|
||||
if (!\array_key_exists($provider, $providers) || !($providers[$provider]['enabled'] ?? false)) {
|
||||
throw new Exception(Exception::PROJECT_PROVIDER_UNSUPPORTED);
|
||||
}
|
||||
|
||||
$actions = Base::getProviderActions();
|
||||
if (!isset($actions[$provider])) {
|
||||
throw new Exception(Exception::PROJECT_PROVIDER_UNSUPPORTED);
|
||||
}
|
||||
|
||||
$updateClass = $actions[$provider];
|
||||
$action = new $updateClass();
|
||||
|
||||
$response->dynamic($action->buildReadResponse($project), $updateClass::getResponseModel());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Project\Http\Project\OAuth2\GitHub;
|
||||
|
||||
use Appwrite\Auth\OAuth2\Github;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Base;
|
||||
use Appwrite\Utopia\Response;
|
||||
|
||||
class Update extends Base
|
||||
{
|
||||
public static function getProviderId(): string
|
||||
{
|
||||
return 'github';
|
||||
}
|
||||
|
||||
public static function getProviderClass(): string
|
||||
{
|
||||
return Github::class;
|
||||
}
|
||||
|
||||
public static function getProviderLabel(): string
|
||||
{
|
||||
return 'GitHub';
|
||||
}
|
||||
|
||||
public static function getProviderSDKMethod(): string
|
||||
{
|
||||
return 'updateOAuth2GitHub';
|
||||
}
|
||||
|
||||
public static function getResponseModel(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_GITHUB;
|
||||
}
|
||||
|
||||
public static function getClientIdName(): string
|
||||
{
|
||||
return 'OAuth 2 app Client ID, or App ID';
|
||||
}
|
||||
|
||||
public static function getClientIdExample(): string
|
||||
{
|
||||
return 'e4d87900000000540733';
|
||||
}
|
||||
|
||||
public static function getClientIdHint(): string
|
||||
{
|
||||
return 'Example of wrong value: 370006';
|
||||
}
|
||||
|
||||
public static function getClientSecretName(): string
|
||||
{
|
||||
return 'Client Secret';
|
||||
}
|
||||
|
||||
public static function getClientSecretExample(): string
|
||||
{
|
||||
return '5e07c00000000000000000000000000000198bcc';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Gitlab;
|
||||
|
||||
use Appwrite\Auth\OAuth2\Gitlab;
|
||||
use Appwrite\Event\Event as QueueEvent;
|
||||
use Appwrite\Platform\Action;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Base;
|
||||
use Appwrite\SDK\AuthType;
|
||||
use Appwrite\SDK\Method;
|
||||
use Appwrite\SDK\Response as SDKResponse;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\Nullable;
|
||||
use Utopia\Validator\Text;
|
||||
use Utopia\Validator\URL;
|
||||
|
||||
class Update extends Base
|
||||
{
|
||||
public static function getProviderId(): string
|
||||
{
|
||||
return 'gitlab';
|
||||
}
|
||||
|
||||
public static function getProviderClass(): string
|
||||
{
|
||||
return Gitlab::class;
|
||||
}
|
||||
|
||||
public static function getProviderLabel(): string
|
||||
{
|
||||
return 'Gitlab';
|
||||
}
|
||||
|
||||
public static function getProviderSDKMethod(): string
|
||||
{
|
||||
return 'updateOAuth2Gitlab';
|
||||
}
|
||||
|
||||
public static function getResponseModel(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_GITLAB;
|
||||
}
|
||||
|
||||
public static function getClientIdParamName(): string
|
||||
{
|
||||
return 'applicationId';
|
||||
}
|
||||
|
||||
public static function getClientSecretParamName(): string
|
||||
{
|
||||
return 'secret';
|
||||
}
|
||||
|
||||
public static function getClientIdName(): string
|
||||
{
|
||||
return 'Application ID';
|
||||
}
|
||||
|
||||
public static function getClientIdExample(): string
|
||||
{
|
||||
return 'd41ffe0000000000000000000000000000000000000000000000000000d5e252';
|
||||
}
|
||||
|
||||
public static function getClientSecretName(): string
|
||||
{
|
||||
return 'Secret';
|
||||
}
|
||||
|
||||
public static function getClientSecretExample(): string
|
||||
{
|
||||
return 'gloas-838cfa0000000000000000000000000000000000000000000000000000ecbb38';
|
||||
}
|
||||
|
||||
public static function getParameters(): array
|
||||
{
|
||||
return \array_merge(parent::getParameters(), [
|
||||
[
|
||||
'$id' => 'endpoint',
|
||||
'name' => 'Endpoint',
|
||||
'example' => 'https://gitlab.com',
|
||||
'hint' => '',
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$providerId = static::getProviderId();
|
||||
$providerLabel = static::getProviderLabel();
|
||||
|
||||
$this
|
||||
->setHttpMethod(Action::HTTP_REQUEST_METHOD_PATCH)
|
||||
->setHttpPath('/v1/project/oauth2/' . $providerId)
|
||||
->desc('Update project OAuth2 ' . $providerLabel)
|
||||
->groups(['api', 'project'])
|
||||
->label('scope', 'oauth2.write')
|
||||
->label('event', 'oauth2.[providerId].update')
|
||||
->label('audits.event', 'project.oauth2.[providerId].update')
|
||||
->label('audits.resource', 'project.oauth2/{response.$id}')
|
||||
->label('sdk', new Method(
|
||||
namespace: 'project',
|
||||
group: 'oauth2',
|
||||
name: static::getProviderSDKMethod(),
|
||||
description: 'Update the project OAuth2 ' . $providerLabel . ' configuration.',
|
||||
auth: [AuthType::ADMIN, AuthType::KEY],
|
||||
responses: [
|
||||
new SDKResponse(
|
||||
code: Response::STATUS_CODE_OK,
|
||||
model: static::getResponseModel(),
|
||||
)
|
||||
],
|
||||
))
|
||||
->param(static::getClientIdParamName(), null, new Nullable(new Text(256, 0)), static::getClientIdDescription(), optional: true)
|
||||
->param(static::getClientSecretParamName(), null, new Nullable(new Text(512, 0)), static::getClientSecretDescription(), optional: true)
|
||||
->param('endpoint', null, new Nullable(new URL(allowEmpty: true)), 'Endpoint URL of self-hosted GitLab instance. For example: https://gitlab.com', optional: true)
|
||||
->param('enabled', null, new Nullable(new Boolean()), 'OAuth2 sign-in method status. Set to true to enable new session creation. Setting to true will trigger end-to-end credentials validation, and will throw if the credentials are invalid.', true)
|
||||
->inject('response')
|
||||
->inject('dbForPlatform')
|
||||
->inject('project')
|
||||
->inject('authorization')
|
||||
->inject('queueForEvents')
|
||||
->callback($this->handle(...));
|
||||
}
|
||||
|
||||
public function buildReadResponse(Document $project): Document
|
||||
{
|
||||
$providerId = static::getProviderId();
|
||||
$oAuthProviders = $project->getAttribute('oAuthProviders', []);
|
||||
$decoded = $this->decodeStoredSecret($project);
|
||||
|
||||
return new Document([
|
||||
'$id' => $providerId,
|
||||
'enabled' => $oAuthProviders[$providerId . 'Enabled'] ?? false,
|
||||
static::getClientIdParamName() => $oAuthProviders[$providerId . 'Appid'] ?? '',
|
||||
static::getClientSecretParamName() => '',
|
||||
'endpoint' => $decoded['endpoint'] ?? '',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom callback used instead of the parent's `action()` because Gitlab
|
||||
* takes an additional `endpoint` parameter. The method is named
|
||||
* differently to avoid an LSP-incompatible override of Base::action().
|
||||
*/
|
||||
public function handle(
|
||||
?string $applicationId,
|
||||
?string $secret,
|
||||
?string $endpoint,
|
||||
?bool $enabled,
|
||||
Response $response,
|
||||
Database $dbForPlatform,
|
||||
Document $project,
|
||||
Authorization $authorization,
|
||||
QueueEvent $queueForEvents
|
||||
): void {
|
||||
$providerId = static::getProviderId();
|
||||
$queueForEvents->setParam('providerId', $providerId);
|
||||
|
||||
// The secret is stored as JSON `{"clientSecret": "...", "endpoint": "..."}`
|
||||
// so that the Gitlab OAuth2 adapter can extract the endpoint via getEndpoint().
|
||||
// Merge the new values with what's already stored so that submitting only
|
||||
// one of `secret`/`endpoint` leaves the other untouched.
|
||||
$encodedSecret = null;
|
||||
if (!\is_null($secret) || !\is_null($endpoint)) {
|
||||
$storedRaw = $project->getAttribute('oAuthProviders', [])[$providerId . 'Secret'] ?? '';
|
||||
$existing = [];
|
||||
if (!empty($storedRaw)) {
|
||||
$existing = \json_decode($storedRaw, true) ?: [];
|
||||
}
|
||||
$encodedSecret = \json_encode([
|
||||
'clientSecret' => $secret ?? ($existing['clientSecret'] ?? ''),
|
||||
'endpoint' => $endpoint ?? ($existing['endpoint'] ?? ''),
|
||||
]);
|
||||
}
|
||||
|
||||
$project = $this->persistCredentials($project, $dbForPlatform, $authorization, $applicationId, $encodedSecret, $enabled);
|
||||
|
||||
// Reuse buildReadResponse to keep PATCH/GET shapes identical and
|
||||
// guarantee the secret is write-only on every response path.
|
||||
$response->dynamic($this->buildReadResponse($project), static::getResponseModel());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Google;
|
||||
|
||||
use Appwrite\Auth\OAuth2\Google;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Base;
|
||||
use Appwrite\Utopia\Response;
|
||||
|
||||
class Update extends Base
|
||||
{
|
||||
public static function getProviderId(): string
|
||||
{
|
||||
return 'google';
|
||||
}
|
||||
|
||||
public static function getProviderClass(): string
|
||||
{
|
||||
return Google::class;
|
||||
}
|
||||
|
||||
public static function getProviderLabel(): string
|
||||
{
|
||||
return 'Google';
|
||||
}
|
||||
|
||||
public static function getProviderSDKMethod(): string
|
||||
{
|
||||
return 'updateOAuth2Google';
|
||||
}
|
||||
|
||||
public static function getResponseModel(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_GOOGLE;
|
||||
}
|
||||
|
||||
public static function getClientIdName(): string
|
||||
{
|
||||
return 'Client ID';
|
||||
}
|
||||
|
||||
public static function getClientIdExample(): string
|
||||
{
|
||||
return '120000000095-92ifjb00000000000000000000g7ijfb.apps.googleusercontent.com';
|
||||
}
|
||||
|
||||
public static function getClientSecretName(): string
|
||||
{
|
||||
return 'Client Secret';
|
||||
}
|
||||
|
||||
public static function getClientSecretExample(): string
|
||||
{
|
||||
return 'GOCSPX-2k8gsR0000000000000000VNahJj';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Keycloak;
|
||||
|
||||
use Appwrite\Auth\OAuth2\Keycloak;
|
||||
use Appwrite\Event\Event as QueueEvent;
|
||||
use Appwrite\Platform\Action;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Base;
|
||||
use Appwrite\SDK\AuthType;
|
||||
use Appwrite\SDK\Method;
|
||||
use Appwrite\SDK\Response as SDKResponse;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\Nullable;
|
||||
use Utopia\Validator\Text;
|
||||
|
||||
class Update extends Base
|
||||
{
|
||||
public static function getProviderId(): string
|
||||
{
|
||||
return 'keycloak';
|
||||
}
|
||||
|
||||
public static function getProviderClass(): string
|
||||
{
|
||||
return Keycloak::class;
|
||||
}
|
||||
|
||||
public static function getProviderLabel(): string
|
||||
{
|
||||
return 'Keycloak';
|
||||
}
|
||||
|
||||
public static function getProviderSDKMethod(): string
|
||||
{
|
||||
return 'updateOAuth2Keycloak';
|
||||
}
|
||||
|
||||
public static function getResponseModel(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_KEYCLOAK;
|
||||
}
|
||||
|
||||
public static function getClientIdName(): string
|
||||
{
|
||||
return 'Client ID';
|
||||
}
|
||||
|
||||
public static function getClientIdExample(): string
|
||||
{
|
||||
return 'appwrite-o0000000st-app';
|
||||
}
|
||||
|
||||
public static function getClientSecretName(): string
|
||||
{
|
||||
return 'Client Secret';
|
||||
}
|
||||
|
||||
public static function getClientSecretExample(): string
|
||||
{
|
||||
return 'jdjrJd00000000000000000000HUsaZO';
|
||||
}
|
||||
|
||||
public static function getParameters(): array
|
||||
{
|
||||
return \array_merge(parent::getParameters(), [
|
||||
[
|
||||
'$id' => 'endpoint',
|
||||
'name' => 'Domain',
|
||||
'example' => 'keycloak.example.com',
|
||||
'hint' => '',
|
||||
],
|
||||
[
|
||||
'$id' => 'realmName',
|
||||
'name' => 'Realm name',
|
||||
'example' => 'appwrite-realm',
|
||||
'hint' => '',
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$providerId = static::getProviderId();
|
||||
$providerLabel = static::getProviderLabel();
|
||||
|
||||
$this
|
||||
->setHttpMethod(Action::HTTP_REQUEST_METHOD_PATCH)
|
||||
->setHttpPath('/v1/project/oauth2/' . $providerId)
|
||||
->desc('Update project OAuth2 ' . $providerLabel)
|
||||
->groups(['api', 'project'])
|
||||
->label('scope', 'oauth2.write')
|
||||
->label('event', 'oauth2.[providerId].update')
|
||||
->label('audits.event', 'project.oauth2.[providerId].update')
|
||||
->label('audits.resource', 'project.oauth2/{response.$id}')
|
||||
->label('sdk', new Method(
|
||||
namespace: 'project',
|
||||
group: 'oauth2',
|
||||
name: static::getProviderSDKMethod(),
|
||||
description: 'Update the project OAuth2 ' . $providerLabel . ' configuration.',
|
||||
auth: [AuthType::ADMIN, AuthType::KEY],
|
||||
responses: [
|
||||
new SDKResponse(
|
||||
code: Response::STATUS_CODE_OK,
|
||||
model: static::getResponseModel(),
|
||||
)
|
||||
],
|
||||
))
|
||||
->param(static::getClientIdParamName(), null, new Nullable(new Text(256, 0)), static::getClientIdDescription(), optional: true)
|
||||
->param(static::getClientSecretParamName(), null, new Nullable(new Text(512, 0)), static::getClientSecretDescription(), optional: true)
|
||||
->param('endpoint', '', new Text(256, 1), 'Domain of Keycloak instance. For example: keycloak.example.com', optional: false)
|
||||
->param('realmName', '', new Text(256, 1), 'Keycloak realm name. For example: appwrite-realm', optional: false)
|
||||
->param('enabled', null, new Nullable(new Boolean()), 'OAuth2 sign-in method status. Set to true to enable new session creation. Setting to true will trigger end-to-end credentials validation, and will throw if the credentials are invalid.', true)
|
||||
->inject('response')
|
||||
->inject('dbForPlatform')
|
||||
->inject('project')
|
||||
->inject('authorization')
|
||||
->inject('queueForEvents')
|
||||
->callback($this->handle(...));
|
||||
}
|
||||
|
||||
public function buildReadResponse(Document $project): Document
|
||||
{
|
||||
$providerId = static::getProviderId();
|
||||
$oAuthProviders = $project->getAttribute('oAuthProviders', []);
|
||||
$decoded = $this->decodeStoredSecret($project);
|
||||
|
||||
return new Document([
|
||||
'$id' => $providerId,
|
||||
'enabled' => $oAuthProviders[$providerId . 'Enabled'] ?? false,
|
||||
static::getClientIdParamName() => $oAuthProviders[$providerId . 'Appid'] ?? '',
|
||||
static::getClientSecretParamName() => '',
|
||||
'endpoint' => $decoded['keycloakDomain'] ?? '',
|
||||
'realmName' => $decoded['keycloakRealm'] ?? '',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom callback used instead of the parent's `action()` because Keycloak
|
||||
* takes additional required `endpoint` and `realmName` parameters. The
|
||||
* method is named differently to avoid an LSP-incompatible override of
|
||||
* Base::action().
|
||||
*/
|
||||
public function handle(
|
||||
?string $clientId,
|
||||
?string $clientSecret,
|
||||
string $endpoint,
|
||||
string $realmName,
|
||||
?bool $enabled,
|
||||
Response $response,
|
||||
Database $dbForPlatform,
|
||||
Document $project,
|
||||
Authorization $authorization,
|
||||
QueueEvent $queueForEvents
|
||||
): void {
|
||||
$providerId = static::getProviderId();
|
||||
$queueForEvents->setParam('providerId', $providerId);
|
||||
|
||||
// The secret is stored as JSON `{"clientSecret": "...", "keycloakDomain": "...", "keycloakRealm": "..."}`
|
||||
// to match the shape Keycloak's OAuth2 adapter expects (getKeycloakDomain(), getKeycloakRealm()).
|
||||
// The `endpoint` and `realmName` params are required on every call, so they're always written.
|
||||
// `clientSecret` is optional; if omitted, the existing stored secret is preserved.
|
||||
$storedRaw = $project->getAttribute('oAuthProviders', [])[$providerId . 'Secret'] ?? '';
|
||||
$existing = [];
|
||||
if (!empty($storedRaw)) {
|
||||
$existing = \json_decode($storedRaw, true) ?: [];
|
||||
}
|
||||
$encodedSecret = \json_encode([
|
||||
'clientSecret' => $clientSecret ?? ($existing['clientSecret'] ?? ''),
|
||||
'keycloakDomain' => $endpoint,
|
||||
'keycloakRealm' => $realmName,
|
||||
]);
|
||||
|
||||
$project = $this->persistCredentials($project, $dbForPlatform, $authorization, $clientId, $encodedSecret, $enabled);
|
||||
|
||||
// Reuse buildReadResponse to keep PATCH/GET shapes identical and
|
||||
// guarantee the clientSecret is write-only on every response path.
|
||||
$response->dynamic($this->buildReadResponse($project), static::getResponseModel());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Kick;
|
||||
|
||||
use Appwrite\Auth\OAuth2\Kick;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Base;
|
||||
use Appwrite\Utopia\Response;
|
||||
|
||||
class Update extends Base
|
||||
{
|
||||
public static function getProviderId(): string
|
||||
{
|
||||
return 'kick';
|
||||
}
|
||||
|
||||
public static function getProviderClass(): string
|
||||
{
|
||||
return Kick::class;
|
||||
}
|
||||
|
||||
public static function getProviderLabel(): string
|
||||
{
|
||||
return 'Kick';
|
||||
}
|
||||
|
||||
public static function getProviderSDKMethod(): string
|
||||
{
|
||||
return 'updateOAuth2Kick';
|
||||
}
|
||||
|
||||
public static function getResponseModel(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_KICK;
|
||||
}
|
||||
|
||||
public static function getClientIdName(): string
|
||||
{
|
||||
return 'Client ID';
|
||||
}
|
||||
|
||||
public static function getClientIdExample(): string
|
||||
{
|
||||
return '01KQ7C00000000000001MFHS32';
|
||||
}
|
||||
|
||||
public static function getClientSecretName(): string
|
||||
{
|
||||
return 'Client Secret';
|
||||
}
|
||||
|
||||
public static function getClientSecretExample(): string
|
||||
{
|
||||
return '34ac5600000000000000000000000000000000000000000000000000e830c8b';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Linkedin;
|
||||
|
||||
use Appwrite\Auth\OAuth2\Linkedin;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Base;
|
||||
use Appwrite\Utopia\Response;
|
||||
|
||||
class Update extends Base
|
||||
{
|
||||
public static function getProviderId(): string
|
||||
{
|
||||
return 'linkedin';
|
||||
}
|
||||
|
||||
public static function getProviderClass(): string
|
||||
{
|
||||
return Linkedin::class;
|
||||
}
|
||||
|
||||
public static function getProviderLabel(): string
|
||||
{
|
||||
return 'Linkedin';
|
||||
}
|
||||
|
||||
public static function getProviderSDKMethod(): string
|
||||
{
|
||||
return 'updateOAuth2Linkedin';
|
||||
}
|
||||
|
||||
public static function getResponseModel(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_LINKEDIN;
|
||||
}
|
||||
|
||||
public static function getClientSecretParamName(): string
|
||||
{
|
||||
return 'primaryClientSecret';
|
||||
}
|
||||
|
||||
public static function getClientIdName(): string
|
||||
{
|
||||
return 'Client ID';
|
||||
}
|
||||
|
||||
public static function getClientIdExample(): string
|
||||
{
|
||||
return '770000000000dv';
|
||||
}
|
||||
|
||||
public static function getClientSecretName(): string
|
||||
{
|
||||
return 'Primary Client Secret or Secondary Client Secret';
|
||||
}
|
||||
|
||||
public static function getClientSecretExample(): string
|
||||
{
|
||||
return 'WPL_AP1.2Bf0000000000000./HtlYw==';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Microsoft;
|
||||
|
||||
use Appwrite\Auth\OAuth2\Microsoft;
|
||||
use Appwrite\Event\Event as QueueEvent;
|
||||
use Appwrite\Platform\Action;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Base;
|
||||
use Appwrite\SDK\AuthType;
|
||||
use Appwrite\SDK\Method;
|
||||
use Appwrite\SDK\Response as SDKResponse;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\Nullable;
|
||||
use Utopia\Validator\Text;
|
||||
|
||||
class Update extends Base
|
||||
{
|
||||
public static function getProviderId(): string
|
||||
{
|
||||
return 'microsoft';
|
||||
}
|
||||
|
||||
public static function getProviderClass(): string
|
||||
{
|
||||
return Microsoft::class;
|
||||
}
|
||||
|
||||
public static function getProviderLabel(): string
|
||||
{
|
||||
return 'Microsoft';
|
||||
}
|
||||
|
||||
public static function getProviderSDKMethod(): string
|
||||
{
|
||||
return 'updateOAuth2Microsoft';
|
||||
}
|
||||
|
||||
public static function getResponseModel(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_MICROSOFT;
|
||||
}
|
||||
|
||||
public static function getClientIdParamName(): string
|
||||
{
|
||||
return 'applicationId';
|
||||
}
|
||||
|
||||
public static function getClientSecretParamName(): string
|
||||
{
|
||||
return 'applicationSecret';
|
||||
}
|
||||
|
||||
public static function getClientIdName(): string
|
||||
{
|
||||
return 'Entra ID Application ID, also known as Client ID';
|
||||
}
|
||||
|
||||
public static function getClientIdExample(): string
|
||||
{
|
||||
return '00001111-aaaa-2222-bbbb-3333cccc4444';
|
||||
}
|
||||
|
||||
public static function getClientSecretName(): string
|
||||
{
|
||||
return 'Entra ID Application Secret, also known as Client Secret';
|
||||
}
|
||||
|
||||
public static function getClientSecretExample(): string
|
||||
{
|
||||
return 'A1bC2dE3fH4iJ5kL6mN7oP8qR9sT0u';
|
||||
}
|
||||
|
||||
public static function getParameters(): array
|
||||
{
|
||||
return \array_merge(parent::getParameters(), [
|
||||
[
|
||||
'$id' => 'tenant',
|
||||
'name' => 'Tenant',
|
||||
'example' => 'common',
|
||||
'hint' => '',
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$providerId = static::getProviderId();
|
||||
$providerLabel = static::getProviderLabel();
|
||||
|
||||
$this
|
||||
->setHttpMethod(Action::HTTP_REQUEST_METHOD_PATCH)
|
||||
->setHttpPath('/v1/project/oauth2/' . $providerId)
|
||||
->desc('Update project OAuth2 ' . $providerLabel)
|
||||
->groups(['api', 'project'])
|
||||
->label('scope', 'oauth2.write')
|
||||
->label('event', 'oauth2.[providerId].update')
|
||||
->label('audits.event', 'project.oauth2.[providerId].update')
|
||||
->label('audits.resource', 'project.oauth2/{response.$id}')
|
||||
->label('sdk', new Method(
|
||||
namespace: 'project',
|
||||
group: 'oauth2',
|
||||
name: static::getProviderSDKMethod(),
|
||||
description: 'Update the project OAuth2 ' . $providerLabel . ' configuration.',
|
||||
auth: [AuthType::ADMIN, AuthType::KEY],
|
||||
responses: [
|
||||
new SDKResponse(
|
||||
code: Response::STATUS_CODE_OK,
|
||||
model: static::getResponseModel(),
|
||||
)
|
||||
],
|
||||
))
|
||||
->param(static::getClientIdParamName(), null, new Nullable(new Text(256, 0)), static::getClientIdDescription(), optional: true)
|
||||
->param(static::getClientSecretParamName(), null, new Nullable(new Text(512, 0)), static::getClientSecretDescription(), optional: true)
|
||||
->param('tenant', '', new Text(256, 1), 'Microsoft Entra ID tenant identifier. Use \'common\', \'organizations\', \'consumers\' or a specific tenant ID. For example: common', optional: false)
|
||||
->param('enabled', null, new Nullable(new Boolean()), 'OAuth2 sign-in method status. Set to true to enable new session creation. Setting to true will trigger end-to-end credentials validation, and will throw if the credentials are invalid.', true)
|
||||
->inject('response')
|
||||
->inject('dbForPlatform')
|
||||
->inject('project')
|
||||
->inject('authorization')
|
||||
->inject('queueForEvents')
|
||||
->callback($this->handle(...));
|
||||
}
|
||||
|
||||
public function buildReadResponse(Document $project): Document
|
||||
{
|
||||
$providerId = static::getProviderId();
|
||||
$oAuthProviders = $project->getAttribute('oAuthProviders', []);
|
||||
$decoded = $this->decodeStoredSecret($project);
|
||||
|
||||
return new Document([
|
||||
'$id' => $providerId,
|
||||
'enabled' => $oAuthProviders[$providerId . 'Enabled'] ?? false,
|
||||
static::getClientIdParamName() => $oAuthProviders[$providerId . 'Appid'] ?? '',
|
||||
static::getClientSecretParamName() => '',
|
||||
'tenant' => $decoded['tenantID'] ?? '',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom callback used instead of the parent's `action()` because Microsoft
|
||||
* takes an additional required `tenant` parameter. The method is named
|
||||
* differently to avoid an LSP-incompatible override of Base::action().
|
||||
*/
|
||||
public function handle(
|
||||
?string $applicationId,
|
||||
?string $applicationSecret,
|
||||
string $tenant,
|
||||
?bool $enabled,
|
||||
Response $response,
|
||||
Database $dbForPlatform,
|
||||
Document $project,
|
||||
Authorization $authorization,
|
||||
QueueEvent $queueForEvents
|
||||
): void {
|
||||
$providerId = static::getProviderId();
|
||||
$queueForEvents->setParam('providerId', $providerId);
|
||||
|
||||
// The secret is stored as JSON `{"clientSecret": "...", "tenantID": "..."}`
|
||||
// to match the shape Microsoft's OAuth2 adapter expects (getTenantID()).
|
||||
// The `tenant` param is required on every call, so it's always written.
|
||||
// `applicationSecret` is optional; if omitted, the existing stored secret is preserved.
|
||||
$storedRaw = $project->getAttribute('oAuthProviders', [])[$providerId . 'Secret'] ?? '';
|
||||
$existing = [];
|
||||
if (!empty($storedRaw)) {
|
||||
$existing = \json_decode($storedRaw, true) ?: [];
|
||||
}
|
||||
$encodedSecret = \json_encode([
|
||||
'clientSecret' => $applicationSecret ?? ($existing['clientSecret'] ?? ''),
|
||||
'tenantID' => $tenant,
|
||||
]);
|
||||
|
||||
$project = $this->persistCredentials($project, $dbForPlatform, $authorization, $applicationId, $encodedSecret, $enabled);
|
||||
|
||||
// Reuse buildReadResponse to keep PATCH/GET shapes identical and
|
||||
// guarantee the applicationSecret is write-only on every response path.
|
||||
$response->dynamic($this->buildReadResponse($project), static::getResponseModel());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Notion;
|
||||
|
||||
use Appwrite\Auth\OAuth2\Notion;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Base;
|
||||
use Appwrite\Utopia\Response;
|
||||
|
||||
class Update extends Base
|
||||
{
|
||||
public static function getProviderId(): string
|
||||
{
|
||||
return 'notion';
|
||||
}
|
||||
|
||||
public static function getProviderClass(): string
|
||||
{
|
||||
return Notion::class;
|
||||
}
|
||||
|
||||
public static function getProviderLabel(): string
|
||||
{
|
||||
return 'Notion';
|
||||
}
|
||||
|
||||
public static function getProviderSDKMethod(): string
|
||||
{
|
||||
return 'updateOAuth2Notion';
|
||||
}
|
||||
|
||||
public static function getResponseModel(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_NOTION;
|
||||
}
|
||||
|
||||
public static function getClientIdParamName(): string
|
||||
{
|
||||
return 'oauthClientId';
|
||||
}
|
||||
|
||||
public static function getClientSecretParamName(): string
|
||||
{
|
||||
return 'oauthClientSecret';
|
||||
}
|
||||
|
||||
public static function getClientIdName(): string
|
||||
{
|
||||
return 'OAuth Client ID';
|
||||
}
|
||||
|
||||
public static function getClientIdExample(): string
|
||||
{
|
||||
return '341d8700-0000-0000-0000-000000446ee3';
|
||||
}
|
||||
|
||||
public static function getClientSecretName(): string
|
||||
{
|
||||
return 'OAuth Client Secret';
|
||||
}
|
||||
|
||||
public static function getClientSecretExample(): string
|
||||
{
|
||||
return 'secret_dLUr4b000000000000000000000000000000lFHAa9';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,230 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Oidc;
|
||||
|
||||
use Appwrite\Auth\OAuth2\Oidc;
|
||||
use Appwrite\Event\Event as QueueEvent;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Platform\Action;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Base;
|
||||
use Appwrite\SDK\AuthType;
|
||||
use Appwrite\SDK\Method;
|
||||
use Appwrite\SDK\Response as SDKResponse;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\Nullable;
|
||||
use Utopia\Validator\Text;
|
||||
use Utopia\Validator\URL;
|
||||
|
||||
class Update extends Base
|
||||
{
|
||||
public static function getProviderId(): string
|
||||
{
|
||||
return 'oidc';
|
||||
}
|
||||
|
||||
public static function getProviderClass(): string
|
||||
{
|
||||
return Oidc::class;
|
||||
}
|
||||
|
||||
public static function getProviderLabel(): string
|
||||
{
|
||||
return 'Oidc';
|
||||
}
|
||||
|
||||
public static function getProviderSDKMethod(): string
|
||||
{
|
||||
return 'updateOAuth2Oidc';
|
||||
}
|
||||
|
||||
public static function getResponseModel(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_OIDC;
|
||||
}
|
||||
|
||||
public static function getClientIdName(): string
|
||||
{
|
||||
return 'Client ID';
|
||||
}
|
||||
|
||||
public static function getClientIdExample(): string
|
||||
{
|
||||
return 'qibI2x0000000000000000000000000006L2YFoG';
|
||||
}
|
||||
|
||||
public static function getClientSecretName(): string
|
||||
{
|
||||
return 'Client Secret';
|
||||
}
|
||||
|
||||
public static function getClientSecretExample(): string
|
||||
{
|
||||
return 'Ah68ed000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003qpcHV';
|
||||
}
|
||||
|
||||
public static function getParameters(): array
|
||||
{
|
||||
return \array_merge(parent::getParameters(), [
|
||||
[
|
||||
'$id' => 'wellKnownURL',
|
||||
'name' => 'Well-known URL',
|
||||
'example' => 'https://myoauth.com/.well-known/openid-configuration',
|
||||
'hint' => '',
|
||||
],
|
||||
[
|
||||
'$id' => 'authorizationURL',
|
||||
'name' => 'Authorization URL',
|
||||
'example' => 'https://myoauth.com/oauth2/authorize',
|
||||
'hint' => '',
|
||||
],
|
||||
[
|
||||
'$id' => 'tokenUrl',
|
||||
'name' => 'Token URL',
|
||||
'example' => 'https://myoauth.com/oauth2/token',
|
||||
'hint' => '',
|
||||
],
|
||||
[
|
||||
'$id' => 'userInfoUrl',
|
||||
'name' => 'User Info URL',
|
||||
'example' => 'https://myoauth.com/oauth2/userinfo',
|
||||
'hint' => '',
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$providerId = static::getProviderId();
|
||||
$providerLabel = static::getProviderLabel();
|
||||
|
||||
$this
|
||||
->setHttpMethod(Action::HTTP_REQUEST_METHOD_PATCH)
|
||||
->setHttpPath('/v1/project/oauth2/' . $providerId)
|
||||
->desc('Update project OAuth2 ' . $providerLabel)
|
||||
->groups(['api', 'project'])
|
||||
->label('scope', 'oauth2.write')
|
||||
->label('event', 'oauth2.[providerId].update')
|
||||
->label('audits.event', 'project.oauth2.[providerId].update')
|
||||
->label('audits.resource', 'project.oauth2/{response.$id}')
|
||||
->label('sdk', new Method(
|
||||
namespace: 'project',
|
||||
group: 'oauth2',
|
||||
name: static::getProviderSDKMethod(),
|
||||
description: 'Update the project OAuth2 ' . $providerLabel . ' configuration.',
|
||||
auth: [AuthType::ADMIN, AuthType::KEY],
|
||||
responses: [
|
||||
new SDKResponse(
|
||||
code: Response::STATUS_CODE_OK,
|
||||
model: static::getResponseModel(),
|
||||
)
|
||||
],
|
||||
))
|
||||
->param(static::getClientIdParamName(), null, new Nullable(new Text(256, 0)), static::getClientIdDescription(), optional: true)
|
||||
->param(static::getClientSecretParamName(), null, new Nullable(new Text(512, 0)), static::getClientSecretDescription(), optional: true)
|
||||
->param('wellKnownURL', null, new Nullable(new URL(allowEmpty: true)), 'OpenID Connect well-known configuration URL. When provided, authorization, token, and user info endpoints can be discovered automatically. For example: https://myoauth.com/.well-known/openid-configuration', optional: true)
|
||||
->param('authorizationURL', null, new Nullable(new URL(allowEmpty: true)), 'OpenID Connect authorization endpoint URL. Required when wellKnownURL is not provided. For example: https://myoauth.com/oauth2/authorize', optional: true)
|
||||
->param('tokenUrl', null, new Nullable(new URL(allowEmpty: true)), 'OpenID Connect token endpoint URL. Required when wellKnownURL is not provided. For example: https://myoauth.com/oauth2/token', optional: true)
|
||||
->param('userInfoUrl', null, new Nullable(new URL(allowEmpty: true)), 'OpenID Connect user info endpoint URL. Required when wellKnownURL is not provided. For example: https://myoauth.com/oauth2/userinfo', optional: true)
|
||||
->param('enabled', null, new Nullable(new Boolean()), 'OAuth2 sign-in method status. Set to true to enable new session creation. Setting to true will trigger end-to-end credentials validation, and will throw if the credentials are invalid.', true)
|
||||
->inject('response')
|
||||
->inject('dbForPlatform')
|
||||
->inject('project')
|
||||
->inject('authorization')
|
||||
->inject('queueForEvents')
|
||||
->callback($this->handle(...));
|
||||
}
|
||||
|
||||
public function buildReadResponse(Document $project): Document
|
||||
{
|
||||
$providerId = static::getProviderId();
|
||||
$oAuthProviders = $project->getAttribute('oAuthProviders', []);
|
||||
$decoded = $this->decodeStoredSecret($project);
|
||||
|
||||
return new Document([
|
||||
'$id' => $providerId,
|
||||
'enabled' => $oAuthProviders[$providerId . 'Enabled'] ?? false,
|
||||
static::getClientIdParamName() => $oAuthProviders[$providerId . 'Appid'] ?? '',
|
||||
static::getClientSecretParamName() => '',
|
||||
'wellKnownURL' => $decoded['wellKnownEndpoint'] ?? '',
|
||||
'authorizationURL' => $decoded['authorizationEndpoint'] ?? '',
|
||||
'tokenUrl' => $decoded['tokenEndpoint'] ?? '',
|
||||
'userInfoUrl' => $decoded['userInfoEndpoint'] ?? '',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom callback used instead of the parent's `action()` because OIDC takes
|
||||
* a well-known URL plus three discovery URLs (authorization, token, user
|
||||
* info), all stored together with the client secret as JSON. The method is
|
||||
* named differently to avoid an LSP-incompatible override of Base::action().
|
||||
*
|
||||
* Enabling the provider requires either a non-empty `wellKnownEndpoint`,
|
||||
* or all three of `authorizationEndpoint`, `tokenEndpoint`, and
|
||||
* `userInfoEndpoint` to be set. The check considers the merged state of
|
||||
* existing stored values plus the new values from the request, so callers
|
||||
* can enable the provider in a single request without re-sending fields
|
||||
* that were configured previously.
|
||||
*/
|
||||
public function handle(
|
||||
?string $clientId,
|
||||
?string $clientSecret,
|
||||
?string $wellKnownURL,
|
||||
?string $authorizationURL,
|
||||
?string $tokenUrl,
|
||||
?string $userInfoUrl,
|
||||
?bool $enabled,
|
||||
Response $response,
|
||||
Database $dbForPlatform,
|
||||
Document $project,
|
||||
Authorization $authorization,
|
||||
QueueEvent $queueForEvents
|
||||
): void {
|
||||
$providerId = static::getProviderId();
|
||||
$queueForEvents->setParam('providerId', $providerId);
|
||||
|
||||
// The secret is stored as JSON
|
||||
// `{"clientSecret": "...", "wellKnownEndpoint": "...", "authorizationEndpoint": "...", "tokenEndpoint": "...", "userInfoEndpoint": "..."}`
|
||||
// so that the OIDC OAuth2 adapter can extract each endpoint individually.
|
||||
// Merge new values with what's already stored so that submitting only a
|
||||
// subset of fields leaves the others untouched.
|
||||
$storedRaw = $project->getAttribute('oAuthProviders', [])[$providerId . 'Secret'] ?? '';
|
||||
$existing = [];
|
||||
if (!empty($storedRaw)) {
|
||||
$existing = \json_decode($storedRaw, true) ?: [];
|
||||
}
|
||||
|
||||
$merged = [
|
||||
'clientSecret' => $clientSecret ?? ($existing['clientSecret'] ?? ''),
|
||||
'wellKnownEndpoint' => $wellKnownURL ?? ($existing['wellKnownEndpoint'] ?? ''),
|
||||
'authorizationEndpoint' => $authorizationURL ?? ($existing['authorizationEndpoint'] ?? ''),
|
||||
'tokenEndpoint' => $tokenUrl ?? ($existing['tokenEndpoint'] ?? ''),
|
||||
'userInfoEndpoint' => $userInfoUrl ?? ($existing['userInfoEndpoint'] ?? ''),
|
||||
];
|
||||
|
||||
// When enabling, require either wellKnownEndpoint alone, or all three
|
||||
// discovery URLs (authorization, token, user info). Skip this check
|
||||
// when disabling or when leaving the enabled flag unchanged.
|
||||
if ($enabled === true) {
|
||||
$hasWellKnown = !empty($merged['wellKnownEndpoint']);
|
||||
$hasAllDiscovery = !empty($merged['authorizationEndpoint'])
|
||||
&& !empty($merged['tokenEndpoint'])
|
||||
&& !empty($merged['userInfoEndpoint']);
|
||||
|
||||
if (!$hasWellKnown && !$hasAllDiscovery) {
|
||||
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'Enabling OpenID Connect requires either wellKnownURL, or all of authorizationURL, tokenUrl, and userInfoUrl.');
|
||||
}
|
||||
}
|
||||
|
||||
$encodedSecret = \json_encode($merged);
|
||||
|
||||
$project = $this->persistCredentials($project, $dbForPlatform, $authorization, $clientId, $encodedSecret, $enabled);
|
||||
|
||||
// Reuse buildReadResponse to keep PATCH/GET shapes identical and
|
||||
// guarantee the clientSecret is write-only on every response path.
|
||||
$response->dynamic($this->buildReadResponse($project), static::getResponseModel());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Okta;
|
||||
|
||||
use Appwrite\Auth\OAuth2\Okta;
|
||||
use Appwrite\Event\Event as QueueEvent;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Platform\Action;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Base;
|
||||
use Appwrite\SDK\AuthType;
|
||||
use Appwrite\SDK\Method;
|
||||
use Appwrite\SDK\Response as SDKResponse;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\Domain as ValidatorDomain;
|
||||
use Utopia\Validator\Nullable;
|
||||
use Utopia\Validator\Text;
|
||||
|
||||
class Update extends Base
|
||||
{
|
||||
public static function getProviderId(): string
|
||||
{
|
||||
return 'okta';
|
||||
}
|
||||
|
||||
public static function getProviderClass(): string
|
||||
{
|
||||
return Okta::class;
|
||||
}
|
||||
|
||||
public static function getProviderLabel(): string
|
||||
{
|
||||
return 'Okta';
|
||||
}
|
||||
|
||||
public static function getProviderSDKMethod(): string
|
||||
{
|
||||
return 'updateOAuth2Okta';
|
||||
}
|
||||
|
||||
public static function getResponseModel(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_OKTA;
|
||||
}
|
||||
|
||||
public static function getClientIdName(): string
|
||||
{
|
||||
return 'Client ID';
|
||||
}
|
||||
|
||||
public static function getClientIdExample(): string
|
||||
{
|
||||
return '0oa00000000000000698';
|
||||
}
|
||||
|
||||
public static function getClientSecretName(): string
|
||||
{
|
||||
return 'Client Secret';
|
||||
}
|
||||
|
||||
public static function getClientSecretExample(): string
|
||||
{
|
||||
return 'Kiq0000000000000000000000000000000000000-00000000000H2L5-3SJ-vRV';
|
||||
}
|
||||
|
||||
public static function getParameters(): array
|
||||
{
|
||||
return \array_merge(parent::getParameters(), [
|
||||
[
|
||||
'$id' => 'domain',
|
||||
'name' => 'Domain',
|
||||
'example' => 'trial-6400025.okta.com',
|
||||
'hint' => 'Example of wrong value: trial-6400025-admin.okta.com, or https://trial-6400025.okta.com/',
|
||||
],
|
||||
[
|
||||
'$id' => 'authorizationServerId',
|
||||
'name' => 'Authorization Server ID',
|
||||
'example' => 'aus000000000000000h7z',
|
||||
'hint' => '',
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$providerId = static::getProviderId();
|
||||
$providerLabel = static::getProviderLabel();
|
||||
|
||||
$this
|
||||
->setHttpMethod(Action::HTTP_REQUEST_METHOD_PATCH)
|
||||
->setHttpPath('/v1/project/oauth2/' . $providerId)
|
||||
->desc('Update project OAuth2 ' . $providerLabel)
|
||||
->groups(['api', 'project'])
|
||||
->label('scope', 'oauth2.write')
|
||||
->label('event', 'oauth2.[providerId].update')
|
||||
->label('audits.event', 'project.oauth2.[providerId].update')
|
||||
->label('audits.resource', 'project.oauth2/{response.$id}')
|
||||
->label('sdk', new Method(
|
||||
namespace: 'project',
|
||||
group: 'oauth2',
|
||||
name: static::getProviderSDKMethod(),
|
||||
description: 'Update the project OAuth2 ' . $providerLabel . ' configuration.',
|
||||
auth: [AuthType::ADMIN, AuthType::KEY],
|
||||
responses: [
|
||||
new SDKResponse(
|
||||
code: Response::STATUS_CODE_OK,
|
||||
model: static::getResponseModel(),
|
||||
)
|
||||
],
|
||||
))
|
||||
->param(static::getClientIdParamName(), null, new Nullable(new Text(256, 0)), static::getClientIdDescription(), optional: true)
|
||||
->param(static::getClientSecretParamName(), null, new Nullable(new Text(512, 0)), static::getClientSecretDescription(), optional: true)
|
||||
->param('domain', null, new Nullable(new ValidatorDomain(allowEmpty: true)), 'Okta company domain. Required when enabling the provider. For example: trial-6400025.okta.com. Example of wrong value: trial-6400025-admin.okta.com, or https://trial-6400025.okta.com/', optional: true)
|
||||
->param('authorizationServerId', null, new Nullable(new Text(256, 0)), 'Custom Authorization Servers. Optional, can be left empty or unconfigured. For example: aus000000000000000h7z', optional: true)
|
||||
->param('enabled', null, new Nullable(new Boolean()), 'OAuth2 sign-in method status. Set to true to enable new session creation. Setting to true will trigger end-to-end credentials validation, and will throw if the credentials are invalid.', true)
|
||||
->inject('response')
|
||||
->inject('dbForPlatform')
|
||||
->inject('project')
|
||||
->inject('authorization')
|
||||
->inject('queueForEvents')
|
||||
->callback($this->handle(...));
|
||||
}
|
||||
|
||||
public function buildReadResponse(Document $project): Document
|
||||
{
|
||||
$providerId = static::getProviderId();
|
||||
$oAuthProviders = $project->getAttribute('oAuthProviders', []);
|
||||
$decoded = $this->decodeStoredSecret($project);
|
||||
|
||||
return new Document([
|
||||
'$id' => $providerId,
|
||||
'enabled' => $oAuthProviders[$providerId . 'Enabled'] ?? false,
|
||||
static::getClientIdParamName() => $oAuthProviders[$providerId . 'Appid'] ?? '',
|
||||
static::getClientSecretParamName() => '',
|
||||
'domain' => $decoded['oktaDomain'] ?? '',
|
||||
'authorizationServerId' => $decoded['authorizationServerId'] ?? '',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom callback used instead of the parent's `action()` because Okta
|
||||
* takes additional optional `domain` and `authorizationServerId` parameters.
|
||||
* The method is named differently to avoid an LSP-incompatible override of
|
||||
* Base::action().
|
||||
*/
|
||||
public function handle(
|
||||
?string $clientId,
|
||||
?string $clientSecret,
|
||||
?string $domain,
|
||||
?string $authorizationServerId,
|
||||
?bool $enabled,
|
||||
Response $response,
|
||||
Database $dbForPlatform,
|
||||
Document $project,
|
||||
Authorization $authorization,
|
||||
QueueEvent $queueForEvents
|
||||
): void {
|
||||
$providerId = static::getProviderId();
|
||||
$queueForEvents->setParam('providerId', $providerId);
|
||||
|
||||
// The secret is stored as JSON `{"clientSecret": "...", "oktaDomain": "...", "authorizationServerId": "..."}`
|
||||
// to match the shape Okta's OAuth2 adapter expects.
|
||||
// Merge new values with existing storage so that submitting only some of
|
||||
// the parameters leaves the others untouched.
|
||||
$storedRaw = $project->getAttribute('oAuthProviders', [])[$providerId . 'Secret'] ?? '';
|
||||
$existing = [];
|
||||
if (!empty($storedRaw)) {
|
||||
$existing = \json_decode($storedRaw, true) ?: [];
|
||||
}
|
||||
|
||||
$encodedSecret = null;
|
||||
if (!\is_null($clientSecret) || !\is_null($domain) || !\is_null($authorizationServerId)) {
|
||||
$encodedSecret = \json_encode([
|
||||
'clientSecret' => $clientSecret ?? ($existing['clientSecret'] ?? ''),
|
||||
'oktaDomain' => $domain ?? ($existing['oktaDomain'] ?? ''),
|
||||
'authorizationServerId' => $authorizationServerId ?? ($existing['authorizationServerId'] ?? ''),
|
||||
]);
|
||||
}
|
||||
|
||||
// Domain is required when enabling the provider, since Okta builds its
|
||||
// authorization, token and userinfo URLs from it.
|
||||
if ($enabled === true) {
|
||||
$effectiveDomain = $domain ?? ($existing['oktaDomain'] ?? '');
|
||||
if (empty($effectiveDomain)) {
|
||||
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'Domain is required when enabling Okta OAuth2 provider.');
|
||||
}
|
||||
}
|
||||
|
||||
$project = $this->persistCredentials($project, $dbForPlatform, $authorization, $clientId, $encodedSecret, $enabled);
|
||||
|
||||
// Reuse buildReadResponse to keep PATCH/GET shapes identical and
|
||||
// guarantee the clientSecret is write-only on every response path.
|
||||
$response->dynamic($this->buildReadResponse($project), static::getResponseModel());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Paypal;
|
||||
|
||||
use Appwrite\Auth\OAuth2\Paypal;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Base;
|
||||
use Appwrite\Utopia\Response;
|
||||
|
||||
class Update extends Base
|
||||
{
|
||||
public static function getProviderId(): string
|
||||
{
|
||||
return 'paypal';
|
||||
}
|
||||
|
||||
public static function getProviderClass(): string
|
||||
{
|
||||
return Paypal::class;
|
||||
}
|
||||
|
||||
public static function getProviderLabel(): string
|
||||
{
|
||||
return 'Paypal';
|
||||
}
|
||||
|
||||
public static function getProviderSDKMethod(): string
|
||||
{
|
||||
return 'updateOAuth2Paypal';
|
||||
}
|
||||
|
||||
public static function getResponseModel(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_PAYPAL;
|
||||
}
|
||||
|
||||
public static function getClientSecretParamName(): string
|
||||
{
|
||||
return 'secretKey';
|
||||
}
|
||||
|
||||
public static function getClientIdName(): string
|
||||
{
|
||||
return 'Client ID';
|
||||
}
|
||||
|
||||
public static function getClientIdExample(): string
|
||||
{
|
||||
return 'AdhIEG7-000000000000-0000000000000000000000000000000-0000000000000000000000-2pyB';
|
||||
}
|
||||
|
||||
public static function getClientSecretName(): string
|
||||
{
|
||||
return 'Secret Key 1 or Secret Key 2';
|
||||
}
|
||||
|
||||
public static function getClientSecretExample(): string
|
||||
{
|
||||
return 'EH8KCXtew--000000000000000000000000000000000000000_C-1_5UP_000000000000000CB7KDp';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Project\Http\Project\OAuth2\PaypalSandbox;
|
||||
|
||||
use Appwrite\Auth\OAuth2\PaypalSandbox;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Paypal\Update as PaypalUpdate;
|
||||
|
||||
class Update extends PaypalUpdate
|
||||
{
|
||||
public static function getProviderId(): string
|
||||
{
|
||||
return 'paypalSandbox';
|
||||
}
|
||||
|
||||
public static function getProviderClass(): string
|
||||
{
|
||||
return PaypalSandbox::class;
|
||||
}
|
||||
|
||||
public static function getProviderLabel(): string
|
||||
{
|
||||
return 'PaypalSandbox';
|
||||
}
|
||||
|
||||
public static function getProviderSDKMethod(): string
|
||||
{
|
||||
return 'updateOAuth2PaypalSandbox';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Podio;
|
||||
|
||||
use Appwrite\Auth\OAuth2\Podio;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Base;
|
||||
use Appwrite\Utopia\Response;
|
||||
|
||||
class Update extends Base
|
||||
{
|
||||
public static function getProviderId(): string
|
||||
{
|
||||
return 'podio';
|
||||
}
|
||||
|
||||
public static function getProviderClass(): string
|
||||
{
|
||||
return Podio::class;
|
||||
}
|
||||
|
||||
public static function getProviderLabel(): string
|
||||
{
|
||||
return 'Podio';
|
||||
}
|
||||
|
||||
public static function getProviderSDKMethod(): string
|
||||
{
|
||||
return 'updateOAuth2Podio';
|
||||
}
|
||||
|
||||
public static function getResponseModel(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_PODIO;
|
||||
}
|
||||
|
||||
public static function getClientIdName(): string
|
||||
{
|
||||
return 'Client ID';
|
||||
}
|
||||
|
||||
public static function getClientIdExample(): string
|
||||
{
|
||||
return 'appwrite-o0000000st-app';
|
||||
}
|
||||
|
||||
public static function getClientSecretName(): string
|
||||
{
|
||||
return 'Client Secret';
|
||||
}
|
||||
|
||||
public static function getClientSecretExample(): string
|
||||
{
|
||||
return 'Rn247T0000000000000000000000000000000000000000000000000000W2zWTN';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Salesforce;
|
||||
|
||||
use Appwrite\Auth\OAuth2\Salesforce;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Base;
|
||||
use Appwrite\Utopia\Response;
|
||||
|
||||
class Update extends Base
|
||||
{
|
||||
public static function getProviderId(): string
|
||||
{
|
||||
return 'salesforce';
|
||||
}
|
||||
|
||||
public static function getProviderClass(): string
|
||||
{
|
||||
return Salesforce::class;
|
||||
}
|
||||
|
||||
public static function getProviderLabel(): string
|
||||
{
|
||||
return 'Salesforce';
|
||||
}
|
||||
|
||||
public static function getProviderSDKMethod(): string
|
||||
{
|
||||
return 'updateOAuth2Salesforce';
|
||||
}
|
||||
|
||||
public static function getResponseModel(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_SALESFORCE;
|
||||
}
|
||||
|
||||
public static function getClientIdParamName(): string
|
||||
{
|
||||
return 'customerKey';
|
||||
}
|
||||
|
||||
public static function getClientSecretParamName(): string
|
||||
{
|
||||
return 'customerSecret';
|
||||
}
|
||||
|
||||
public static function getClientIdName(): string
|
||||
{
|
||||
return 'Consumer Key';
|
||||
}
|
||||
|
||||
public static function getClientIdExample(): string
|
||||
{
|
||||
return '3MVG9I0000000000000000000000000000000000000000000000000000000000000000000000000C5Aejq';
|
||||
}
|
||||
|
||||
public static function getClientSecretName(): string
|
||||
{
|
||||
return 'Consumer Secret';
|
||||
}
|
||||
|
||||
public static function getClientSecretExample(): string
|
||||
{
|
||||
return '3w000000000000e2';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Slack;
|
||||
|
||||
use Appwrite\Auth\OAuth2\Slack;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Base;
|
||||
use Appwrite\Utopia\Response;
|
||||
|
||||
class Update extends Base
|
||||
{
|
||||
public static function getProviderId(): string
|
||||
{
|
||||
return 'slack';
|
||||
}
|
||||
|
||||
public static function getProviderClass(): string
|
||||
{
|
||||
return Slack::class;
|
||||
}
|
||||
|
||||
public static function getProviderLabel(): string
|
||||
{
|
||||
return 'Slack';
|
||||
}
|
||||
|
||||
public static function getProviderSDKMethod(): string
|
||||
{
|
||||
return 'updateOAuth2Slack';
|
||||
}
|
||||
|
||||
public static function getResponseModel(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_SLACK;
|
||||
}
|
||||
|
||||
public static function getClientIdName(): string
|
||||
{
|
||||
return 'Client ID';
|
||||
}
|
||||
|
||||
public static function getClientIdExample(): string
|
||||
{
|
||||
return '23000000089.15000000000023';
|
||||
}
|
||||
|
||||
public static function getClientSecretName(): string
|
||||
{
|
||||
return 'Client Secret';
|
||||
}
|
||||
|
||||
public static function getClientSecretExample(): string
|
||||
{
|
||||
return '81656000000000000000000000f3d2fd';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Spotify;
|
||||
|
||||
use Appwrite\Auth\OAuth2\Spotify;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Base;
|
||||
use Appwrite\Utopia\Response;
|
||||
|
||||
class Update extends Base
|
||||
{
|
||||
public static function getProviderId(): string
|
||||
{
|
||||
return 'spotify';
|
||||
}
|
||||
|
||||
public static function getProviderClass(): string
|
||||
{
|
||||
return Spotify::class;
|
||||
}
|
||||
|
||||
public static function getProviderLabel(): string
|
||||
{
|
||||
return 'Spotify';
|
||||
}
|
||||
|
||||
public static function getProviderSDKMethod(): string
|
||||
{
|
||||
return 'updateOAuth2Spotify';
|
||||
}
|
||||
|
||||
public static function getResponseModel(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_SPOTIFY;
|
||||
}
|
||||
|
||||
public static function getClientIdName(): string
|
||||
{
|
||||
return 'Client ID';
|
||||
}
|
||||
|
||||
public static function getClientIdExample(): string
|
||||
{
|
||||
return '6ec271000000000000000000009beace';
|
||||
}
|
||||
|
||||
public static function getClientSecretName(): string
|
||||
{
|
||||
return 'Client Secret';
|
||||
}
|
||||
|
||||
public static function getClientSecretExample(): string
|
||||
{
|
||||
return 'db068a000000000000000000008b5b9f';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Stripe;
|
||||
|
||||
use Appwrite\Auth\OAuth2\Stripe;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Base;
|
||||
use Appwrite\Utopia\Response;
|
||||
|
||||
class Update extends Base
|
||||
{
|
||||
public static function getProviderId(): string
|
||||
{
|
||||
return 'stripe';
|
||||
}
|
||||
|
||||
public static function getProviderClass(): string
|
||||
{
|
||||
return Stripe::class;
|
||||
}
|
||||
|
||||
public static function getProviderLabel(): string
|
||||
{
|
||||
return 'Stripe';
|
||||
}
|
||||
|
||||
public static function getProviderSDKMethod(): string
|
||||
{
|
||||
return 'updateOAuth2Stripe';
|
||||
}
|
||||
|
||||
public static function getResponseModel(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_STRIPE;
|
||||
}
|
||||
|
||||
public static function getClientSecretParamName(): string
|
||||
{
|
||||
return 'apiSecretKey';
|
||||
}
|
||||
|
||||
public static function getClientIdName(): string
|
||||
{
|
||||
return 'Client ID';
|
||||
}
|
||||
|
||||
public static function getClientIdExample(): string
|
||||
{
|
||||
return 'ca_UKibXX0000000000000000000006byvR';
|
||||
}
|
||||
|
||||
public static function getClientSecretName(): string
|
||||
{
|
||||
return 'API Secret Key';
|
||||
}
|
||||
|
||||
public static function getClientSecretExample(): string
|
||||
{
|
||||
return 'sk_51SfOd000000000000000000000000000000000000000000000000000000000000000000000000000000000000000QGWYfp';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Tradeshift;
|
||||
|
||||
use Appwrite\Auth\OAuth2\Tradeshift;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Base;
|
||||
use Appwrite\Utopia\Response;
|
||||
|
||||
class Update extends Base
|
||||
{
|
||||
public static function getProviderId(): string
|
||||
{
|
||||
return 'tradeshift';
|
||||
}
|
||||
|
||||
public static function getProviderClass(): string
|
||||
{
|
||||
return Tradeshift::class;
|
||||
}
|
||||
|
||||
public static function getProviderLabel(): string
|
||||
{
|
||||
return 'Tradeshift';
|
||||
}
|
||||
|
||||
public static function getProviderSDKMethod(): string
|
||||
{
|
||||
return 'updateOAuth2Tradeshift';
|
||||
}
|
||||
|
||||
public static function getResponseModel(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_TRADESHIFT;
|
||||
}
|
||||
|
||||
public static function getClientIdParamName(): string
|
||||
{
|
||||
return 'oauth2ClientId';
|
||||
}
|
||||
|
||||
public static function getClientSecretParamName(): string
|
||||
{
|
||||
return 'oauth2ClientSecret';
|
||||
}
|
||||
|
||||
public static function getClientIdName(): string
|
||||
{
|
||||
return 'OAuth2 Client ID';
|
||||
}
|
||||
|
||||
public static function getClientIdExample(): string
|
||||
{
|
||||
return 'appwrite-tes00000.0000000000est-app';
|
||||
}
|
||||
|
||||
public static function getClientSecretName(): string
|
||||
{
|
||||
return 'OAuth2 Client Secret';
|
||||
}
|
||||
|
||||
public static function getClientSecretExample(): string
|
||||
{
|
||||
return '7cb52700-0000-0000-0000-000000ca5b83';
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Project\Http\Project\OAuth2\TradeshiftSandbox;
|
||||
|
||||
use Appwrite\Auth\OAuth2\TradeshiftBox;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Tradeshift\Update as TradeshiftUpdate;
|
||||
|
||||
class Update extends TradeshiftUpdate
|
||||
{
|
||||
public static function getProviderId(): string
|
||||
{
|
||||
return 'tradeshiftBox';
|
||||
}
|
||||
|
||||
public static function getProviderClass(): string
|
||||
{
|
||||
return TradeshiftBox::class;
|
||||
}
|
||||
|
||||
public static function getProviderLabel(): string
|
||||
{
|
||||
return 'Tradeshift Sandbox';
|
||||
}
|
||||
|
||||
public static function getProviderSDKMethod(): string
|
||||
{
|
||||
return 'updateOAuth2TradeshiftSandbox';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Twitch;
|
||||
|
||||
use Appwrite\Auth\OAuth2\Twitch;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Base;
|
||||
use Appwrite\Utopia\Response;
|
||||
|
||||
class Update extends Base
|
||||
{
|
||||
public static function getProviderId(): string
|
||||
{
|
||||
return 'twitch';
|
||||
}
|
||||
|
||||
public static function getProviderClass(): string
|
||||
{
|
||||
return Twitch::class;
|
||||
}
|
||||
|
||||
public static function getProviderLabel(): string
|
||||
{
|
||||
return 'Twitch';
|
||||
}
|
||||
|
||||
public static function getProviderSDKMethod(): string
|
||||
{
|
||||
return 'updateOAuth2Twitch';
|
||||
}
|
||||
|
||||
public static function getResponseModel(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_TWITCH;
|
||||
}
|
||||
|
||||
public static function getClientIdName(): string
|
||||
{
|
||||
return 'Client ID';
|
||||
}
|
||||
|
||||
public static function getClientIdExample(): string
|
||||
{
|
||||
return 'vvi0in000000000000000000ikmt9p';
|
||||
}
|
||||
|
||||
public static function getClientSecretName(): string
|
||||
{
|
||||
return 'Client Secret';
|
||||
}
|
||||
|
||||
public static function getClientSecretExample(): string
|
||||
{
|
||||
return 'pmapue000000000000000000zylw3v';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Project\Http\Project\OAuth2\WordPress;
|
||||
|
||||
use Appwrite\Auth\OAuth2\WordPress;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Base;
|
||||
use Appwrite\Utopia\Response;
|
||||
|
||||
class Update extends Base
|
||||
{
|
||||
public static function getProviderId(): string
|
||||
{
|
||||
return 'wordpress';
|
||||
}
|
||||
|
||||
public static function getProviderClass(): string
|
||||
{
|
||||
return WordPress::class;
|
||||
}
|
||||
|
||||
public static function getProviderLabel(): string
|
||||
{
|
||||
return 'WordPress';
|
||||
}
|
||||
|
||||
public static function getProviderSDKMethod(): string
|
||||
{
|
||||
return 'updateOAuth2WordPress';
|
||||
}
|
||||
|
||||
public static function getResponseModel(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_WORDPRESS;
|
||||
}
|
||||
|
||||
public static function getClientIdName(): string
|
||||
{
|
||||
return 'Client ID';
|
||||
}
|
||||
|
||||
public static function getClientIdExample(): string
|
||||
{
|
||||
return '130005';
|
||||
}
|
||||
|
||||
public static function getClientSecretName(): string
|
||||
{
|
||||
return 'Client Secret';
|
||||
}
|
||||
|
||||
public static function getClientSecretExample(): string
|
||||
{
|
||||
return 'PlBfJS0000000000000000000000000000000000000000000000000000EdUZJk';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Project\Http\Project\OAuth2\X;
|
||||
|
||||
use Appwrite\Auth\OAuth2\X;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Base;
|
||||
use Appwrite\Utopia\Response;
|
||||
|
||||
class Update extends Base
|
||||
{
|
||||
public static function getProviderId(): string
|
||||
{
|
||||
return 'x';
|
||||
}
|
||||
|
||||
public static function getProviderClass(): string
|
||||
{
|
||||
return X::class;
|
||||
}
|
||||
|
||||
public static function getProviderLabel(): string
|
||||
{
|
||||
return 'X';
|
||||
}
|
||||
|
||||
public static function getProviderSDKMethod(): string
|
||||
{
|
||||
return 'updateOAuth2X';
|
||||
}
|
||||
|
||||
public static function getResponseModel(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_X;
|
||||
}
|
||||
|
||||
public static function getClientIdParamName(): string
|
||||
{
|
||||
return 'customerKey';
|
||||
}
|
||||
|
||||
public static function getClientSecretParamName(): string
|
||||
{
|
||||
return 'secretKey';
|
||||
}
|
||||
|
||||
public static function getClientIdName(): string
|
||||
{
|
||||
return 'Customer Key';
|
||||
}
|
||||
|
||||
public static function getClientIdExample(): string
|
||||
{
|
||||
return 'slzZV0000000000000NFLaWT';
|
||||
}
|
||||
|
||||
public static function getClientSecretName(): string
|
||||
{
|
||||
return 'Secret Key';
|
||||
}
|
||||
|
||||
public static function getClientSecretExample(): string
|
||||
{
|
||||
return 'tkEPkp00000000000000000000000000000000000000FTxbI9';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Project\Http\Project\OAuth2;
|
||||
|
||||
use Appwrite\SDK\AuthType;
|
||||
use Appwrite\SDK\Method;
|
||||
use Appwrite\SDK\Response as SDKResponse;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Platform\Action;
|
||||
use Utopia\Platform\Scope\HTTP;
|
||||
|
||||
class XList extends Action
|
||||
{
|
||||
use HTTP;
|
||||
|
||||
public static function getName()
|
||||
{
|
||||
return 'listProjectOAuth2';
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this
|
||||
->setHttpMethod(Action::HTTP_REQUEST_METHOD_GET)
|
||||
->setHttpPath('/v1/project/oauth2')
|
||||
->desc('List project OAuth2 providers')
|
||||
->groups(['api', 'project'])
|
||||
->label('scope', 'oauth2.read')
|
||||
->label('sdk', new Method(
|
||||
namespace: 'project',
|
||||
group: 'oauth2',
|
||||
name: 'listOAuth2Providers',
|
||||
description: <<<EOT
|
||||
Get a list of all OAuth2 providers supported by the server, along with the project's configuration for each. Credential fields are write-only and always returned empty.
|
||||
EOT,
|
||||
auth: [AuthType::ADMIN, AuthType::KEY],
|
||||
responses: [
|
||||
new SDKResponse(
|
||||
code: Response::STATUS_CODE_OK,
|
||||
model: Response::MODEL_OAUTH2_PROVIDER_LIST,
|
||||
)
|
||||
]
|
||||
))
|
||||
->inject('response')
|
||||
->inject('project')
|
||||
->callback($this->action(...));
|
||||
}
|
||||
|
||||
public function action(
|
||||
Response $response,
|
||||
Document $project,
|
||||
): void {
|
||||
$providers = Config::getParam('oAuthProviders', []);
|
||||
$actions = Base::getProviderActions();
|
||||
|
||||
$documents = [];
|
||||
foreach ($actions as $providerId => $updateClass) {
|
||||
if (!($providers[$providerId]['enabled'] ?? false)) {
|
||||
// Disabled by Appwrite configuration, exclude from response
|
||||
continue;
|
||||
}
|
||||
|
||||
$action = new $updateClass();
|
||||
$documents[] = $action->buildReadResponse($project);
|
||||
}
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'total' => \count($documents),
|
||||
'providers' => $documents,
|
||||
]), Response::MODEL_OAUTH2_PROVIDER_LIST);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Yahoo;
|
||||
|
||||
use Appwrite\Auth\OAuth2\Yahoo;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Base;
|
||||
use Appwrite\Utopia\Response;
|
||||
|
||||
class Update extends Base
|
||||
{
|
||||
public static function getProviderId(): string
|
||||
{
|
||||
return 'yahoo';
|
||||
}
|
||||
|
||||
public static function getProviderClass(): string
|
||||
{
|
||||
return Yahoo::class;
|
||||
}
|
||||
|
||||
public static function getProviderLabel(): string
|
||||
{
|
||||
return 'Yahoo';
|
||||
}
|
||||
|
||||
public static function getProviderSDKMethod(): string
|
||||
{
|
||||
return 'updateOAuth2Yahoo';
|
||||
}
|
||||
|
||||
public static function getResponseModel(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_YAHOO;
|
||||
}
|
||||
|
||||
public static function getClientIdName(): string
|
||||
{
|
||||
return 'Client ID, also known as Customer Key';
|
||||
}
|
||||
|
||||
public static function getClientIdExample(): string
|
||||
{
|
||||
return 'dj0yJm000000000000000000000000000000000000000000000000000000000000000000000000000000000000Z4PWRm';
|
||||
}
|
||||
|
||||
public static function getClientSecretName(): string
|
||||
{
|
||||
return 'Client Secret, also known as Customer Secret';
|
||||
}
|
||||
|
||||
public static function getClientSecretExample(): string
|
||||
{
|
||||
return 'cf978f0000000000000000000000000000c5e2e9';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Yandex;
|
||||
|
||||
use Appwrite\Auth\OAuth2\Yandex;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Base;
|
||||
use Appwrite\Utopia\Response;
|
||||
|
||||
class Update extends Base
|
||||
{
|
||||
public static function getProviderId(): string
|
||||
{
|
||||
return 'yandex';
|
||||
}
|
||||
|
||||
public static function getProviderClass(): string
|
||||
{
|
||||
return Yandex::class;
|
||||
}
|
||||
|
||||
public static function getProviderLabel(): string
|
||||
{
|
||||
return 'Yandex';
|
||||
}
|
||||
|
||||
public static function getProviderSDKMethod(): string
|
||||
{
|
||||
return 'updateOAuth2Yandex';
|
||||
}
|
||||
|
||||
public static function getResponseModel(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_YANDEX;
|
||||
}
|
||||
|
||||
public static function getClientIdName(): string
|
||||
{
|
||||
return 'Client ID';
|
||||
}
|
||||
|
||||
public static function getClientIdExample(): string
|
||||
{
|
||||
return '6a8a6a0000000000000000000091483c';
|
||||
}
|
||||
|
||||
public static function getClientSecretName(): string
|
||||
{
|
||||
return 'Client Secret';
|
||||
}
|
||||
|
||||
public static function getClientSecretExample(): string
|
||||
{
|
||||
return 'bbf98500000000000000000000c75a63';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Zoho;
|
||||
|
||||
use Appwrite\Auth\OAuth2\Zoho;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Base;
|
||||
use Appwrite\Utopia\Response;
|
||||
|
||||
class Update extends Base
|
||||
{
|
||||
public static function getProviderId(): string
|
||||
{
|
||||
return 'zoho';
|
||||
}
|
||||
|
||||
public static function getProviderClass(): string
|
||||
{
|
||||
return Zoho::class;
|
||||
}
|
||||
|
||||
public static function getProviderLabel(): string
|
||||
{
|
||||
return 'Zoho';
|
||||
}
|
||||
|
||||
public static function getProviderSDKMethod(): string
|
||||
{
|
||||
return 'updateOAuth2Zoho';
|
||||
}
|
||||
|
||||
public static function getResponseModel(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_ZOHO;
|
||||
}
|
||||
|
||||
public static function getClientIdName(): string
|
||||
{
|
||||
return 'Client ID';
|
||||
}
|
||||
|
||||
public static function getClientIdExample(): string
|
||||
{
|
||||
return '1000.83C178000000000000000000RPNX0B';
|
||||
}
|
||||
|
||||
public static function getClientSecretName(): string
|
||||
{
|
||||
return 'Client Secret';
|
||||
}
|
||||
|
||||
public static function getClientSecretExample(): string
|
||||
{
|
||||
return 'fb5cac000000000000000000000000000000a68f6e';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Zoom;
|
||||
|
||||
use Appwrite\Auth\OAuth2\Zoom;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Base;
|
||||
use Appwrite\Utopia\Response;
|
||||
|
||||
class Update extends Base
|
||||
{
|
||||
public static function getProviderId(): string
|
||||
{
|
||||
return 'zoom';
|
||||
}
|
||||
|
||||
public static function getProviderClass(): string
|
||||
{
|
||||
return Zoom::class;
|
||||
}
|
||||
|
||||
public static function getProviderLabel(): string
|
||||
{
|
||||
return 'Zoom';
|
||||
}
|
||||
|
||||
public static function getProviderSDKMethod(): string
|
||||
{
|
||||
return 'updateOAuth2Zoom';
|
||||
}
|
||||
|
||||
public static function getResponseModel(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_ZOOM;
|
||||
}
|
||||
|
||||
public static function getClientIdName(): string
|
||||
{
|
||||
return 'Client ID';
|
||||
}
|
||||
|
||||
public static function getClientIdExample(): string
|
||||
{
|
||||
return 'QMAC00000000000000w0AQ';
|
||||
}
|
||||
|
||||
public static function getClientSecretName(): string
|
||||
{
|
||||
return 'Client Secret';
|
||||
}
|
||||
|
||||
public static function getClientSecretExample(): string
|
||||
{
|
||||
return 'GAWsG4000000000000000000007U01ON';
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,50 @@ use Appwrite\Platform\Modules\Project\Http\Project\MockPhone\Delete as DeleteMoc
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\MockPhone\Get as GetMockPhone;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\MockPhone\Update as UpdateMockPhone;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\MockPhone\XList as ListMockPhones;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Amazon\Update as UpdateOAuth2Amazon;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Apple\Update as UpdateOAuth2Apple;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Auth0\Update as UpdateOAuth2Auth0;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Authentik\Update as UpdateOAuth2Authentik;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Autodesk\Update as UpdateOAuth2Autodesk;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Bitbucket\Update as UpdateOAuth2Bitbucket;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Bitly\Update as UpdateOAuth2Bitly;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Box\Update as UpdateOAuth2Box;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Dailymotion\Update as UpdateOAuth2Dailymotion;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Discord\Update as UpdateOAuth2Discord;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Disqus\Update as UpdateOAuth2Disqus;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Dropbox\Update as UpdateOAuth2Dropbox;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Etsy\Update as UpdateOAuth2Etsy;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Facebook\Update as UpdateOAuth2Facebook;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Figma\Update as UpdateOAuth2Figma;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\FusionAuth\Update as UpdateOAuth2FusionAuth;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Get as GetOAuth2Provider;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\GitHub\Update as UpdateOAuth2GitHub;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Gitlab\Update as UpdateOAuth2Gitlab;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Google\Update as UpdateOAuth2Google;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Keycloak\Update as UpdateOAuth2Keycloak;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Kick\Update as UpdateOAuth2Kick;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Linkedin\Update as UpdateOAuth2Linkedin;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Microsoft\Update as UpdateOAuth2Microsoft;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Notion\Update as UpdateOAuth2Notion;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Oidc\Update as UpdateOAuth2Oidc;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Okta\Update as UpdateOAuth2Okta;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Paypal\Update as UpdateOAuth2Paypal;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\PaypalSandbox\Update as UpdateOAuth2PaypalSandbox;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Podio\Update as UpdateOAuth2Podio;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Salesforce\Update as UpdateOAuth2Salesforce;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Slack\Update as UpdateOAuth2Slack;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Spotify\Update as UpdateOAuth2Spotify;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Stripe\Update as UpdateOAuth2Stripe;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Tradeshift\Update as UpdateOAuth2Tradeshift;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\TradeshiftSandbox\Update as UpdateOAuth2TradeshiftSandbox;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Twitch\Update as UpdateOAuth2Twitch;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\WordPress\Update as UpdateOAuth2WordPress;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\X\Update as UpdateOAuth2X;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\XList as ListOAuth2Providers;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Yahoo\Update as UpdateOAuth2Yahoo;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Yandex\Update as UpdateOAuth2Yandex;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Zoho\Update as UpdateOAuth2Zoho;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Zoom\Update as UpdateOAuth2Zoom;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\Platforms\Android\Create as CreateAndroidPlatform;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\Platforms\Android\Update as UpdateAndroidPlatform;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\Platforms\Apple\Create as CreateApplePlatform;
|
||||
@@ -129,5 +173,51 @@ class Http extends Service
|
||||
|
||||
// Auth Methods
|
||||
$this->addAction(UpdateAuthMethod::getName(), new UpdateAuthMethod());
|
||||
|
||||
// OAuth2
|
||||
$this->addAction(ListOAuth2Providers::getName(), new ListOAuth2Providers());
|
||||
$this->addAction(GetOAuth2Provider::getName(), new GetOAuth2Provider());
|
||||
$this->addAction(UpdateOAuth2GitHub::getName(), new UpdateOAuth2GitHub());
|
||||
$this->addAction(UpdateOAuth2Discord::getName(), new UpdateOAuth2Discord());
|
||||
$this->addAction(UpdateOAuth2Figma::getName(), new UpdateOAuth2Figma());
|
||||
$this->addAction(UpdateOAuth2Dropbox::getName(), new UpdateOAuth2Dropbox());
|
||||
$this->addAction(UpdateOAuth2Dailymotion::getName(), new UpdateOAuth2Dailymotion());
|
||||
$this->addAction(UpdateOAuth2Bitbucket::getName(), new UpdateOAuth2Bitbucket());
|
||||
$this->addAction(UpdateOAuth2Bitly::getName(), new UpdateOAuth2Bitly());
|
||||
$this->addAction(UpdateOAuth2Box::getName(), new UpdateOAuth2Box());
|
||||
$this->addAction(UpdateOAuth2Autodesk::getName(), new UpdateOAuth2Autodesk());
|
||||
$this->addAction(UpdateOAuth2Google::getName(), new UpdateOAuth2Google());
|
||||
$this->addAction(UpdateOAuth2Zoom::getName(), new UpdateOAuth2Zoom());
|
||||
$this->addAction(UpdateOAuth2Zoho::getName(), new UpdateOAuth2Zoho());
|
||||
$this->addAction(UpdateOAuth2Yandex::getName(), new UpdateOAuth2Yandex());
|
||||
$this->addAction(UpdateOAuth2X::getName(), new UpdateOAuth2X());
|
||||
$this->addAction(UpdateOAuth2WordPress::getName(), new UpdateOAuth2WordPress());
|
||||
$this->addAction(UpdateOAuth2Twitch::getName(), new UpdateOAuth2Twitch());
|
||||
$this->addAction(UpdateOAuth2Stripe::getName(), new UpdateOAuth2Stripe());
|
||||
$this->addAction(UpdateOAuth2Spotify::getName(), new UpdateOAuth2Spotify());
|
||||
$this->addAction(UpdateOAuth2Slack::getName(), new UpdateOAuth2Slack());
|
||||
$this->addAction(UpdateOAuth2Podio::getName(), new UpdateOAuth2Podio());
|
||||
$this->addAction(UpdateOAuth2Notion::getName(), new UpdateOAuth2Notion());
|
||||
$this->addAction(UpdateOAuth2Salesforce::getName(), new UpdateOAuth2Salesforce());
|
||||
$this->addAction(UpdateOAuth2Yahoo::getName(), new UpdateOAuth2Yahoo());
|
||||
$this->addAction(UpdateOAuth2Linkedin::getName(), new UpdateOAuth2Linkedin());
|
||||
$this->addAction(UpdateOAuth2Disqus::getName(), new UpdateOAuth2Disqus());
|
||||
$this->addAction(UpdateOAuth2Amazon::getName(), new UpdateOAuth2Amazon());
|
||||
$this->addAction(UpdateOAuth2Etsy::getName(), new UpdateOAuth2Etsy());
|
||||
$this->addAction(UpdateOAuth2Facebook::getName(), new UpdateOAuth2Facebook());
|
||||
$this->addAction(UpdateOAuth2Tradeshift::getName(), new UpdateOAuth2Tradeshift());
|
||||
$this->addAction(UpdateOAuth2TradeshiftSandbox::getName(), new UpdateOAuth2TradeshiftSandbox());
|
||||
$this->addAction(UpdateOAuth2Paypal::getName(), new UpdateOAuth2Paypal());
|
||||
$this->addAction(UpdateOAuth2PaypalSandbox::getName(), new UpdateOAuth2PaypalSandbox());
|
||||
$this->addAction(UpdateOAuth2Gitlab::getName(), new UpdateOAuth2Gitlab());
|
||||
$this->addAction(UpdateOAuth2Authentik::getName(), new UpdateOAuth2Authentik());
|
||||
$this->addAction(UpdateOAuth2Auth0::getName(), new UpdateOAuth2Auth0());
|
||||
$this->addAction(UpdateOAuth2FusionAuth::getName(), new UpdateOAuth2FusionAuth());
|
||||
$this->addAction(UpdateOAuth2Keycloak::getName(), new UpdateOAuth2Keycloak());
|
||||
$this->addAction(UpdateOAuth2Oidc::getName(), new UpdateOAuth2Oidc());
|
||||
$this->addAction(UpdateOAuth2Okta::getName(), new UpdateOAuth2Okta());
|
||||
$this->addAction(UpdateOAuth2Kick::getName(), new UpdateOAuth2Kick());
|
||||
$this->addAction(UpdateOAuth2Apple::getName(), new UpdateOAuth2Apple());
|
||||
$this->addAction(UpdateOAuth2Microsoft::getName(), new UpdateOAuth2Microsoft());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -391,6 +391,8 @@ class Migrations extends Action
|
||||
'keys.write',
|
||||
'platforms.read',
|
||||
'platforms.write',
|
||||
'oauth2.read',
|
||||
'oauth2.write',
|
||||
'mocks.read',
|
||||
'mocks.write',
|
||||
'policies.read',
|
||||
|
||||
@@ -278,6 +278,47 @@ class Response extends SwooleResponse
|
||||
public const MODEL_VCS = 'vcs';
|
||||
public const MODEL_EMAIL_TEMPLATE = 'emailTemplate';
|
||||
public const MODEL_EMAIL_TEMPLATE_LIST = 'emailTemplateList';
|
||||
public const MODEL_OAUTH2_GITHUB = 'oAuth2Github';
|
||||
public const MODEL_OAUTH2_DISCORD = 'oAuth2Discord';
|
||||
public const MODEL_OAUTH2_FIGMA = 'oAuth2Figma';
|
||||
public const MODEL_OAUTH2_DROPBOX = 'oAuth2Dropbox';
|
||||
public const MODEL_OAUTH2_DAILYMOTION = 'oAuth2Dailymotion';
|
||||
public const MODEL_OAUTH2_BITBUCKET = 'oAuth2Bitbucket';
|
||||
public const MODEL_OAUTH2_BITLY = 'oAuth2Bitly';
|
||||
public const MODEL_OAUTH2_BOX = 'oAuth2Box';
|
||||
public const MODEL_OAUTH2_AUTODESK = 'oAuth2Autodesk';
|
||||
public const MODEL_OAUTH2_GOOGLE = 'oAuth2Google';
|
||||
public const MODEL_OAUTH2_ZOOM = 'oAuth2Zoom';
|
||||
public const MODEL_OAUTH2_ZOHO = 'oAuth2Zoho';
|
||||
public const MODEL_OAUTH2_YANDEX = 'oAuth2Yandex';
|
||||
public const MODEL_OAUTH2_X = 'oAuth2X';
|
||||
public const MODEL_OAUTH2_WORDPRESS = 'oAuth2WordPress';
|
||||
public const MODEL_OAUTH2_TWITCH = 'oAuth2Twitch';
|
||||
public const MODEL_OAUTH2_STRIPE = 'oAuth2Stripe';
|
||||
public const MODEL_OAUTH2_SPOTIFY = 'oAuth2Spotify';
|
||||
public const MODEL_OAUTH2_SLACK = 'oAuth2Slack';
|
||||
public const MODEL_OAUTH2_PODIO = 'oAuth2Podio';
|
||||
public const MODEL_OAUTH2_NOTION = 'oAuth2Notion';
|
||||
public const MODEL_OAUTH2_SALESFORCE = 'oAuth2Salesforce';
|
||||
public const MODEL_OAUTH2_YAHOO = 'oAuth2Yahoo';
|
||||
public const MODEL_OAUTH2_LINKEDIN = 'oAuth2Linkedin';
|
||||
public const MODEL_OAUTH2_DISQUS = 'oAuth2Disqus';
|
||||
public const MODEL_OAUTH2_AMAZON = 'oAuth2Amazon';
|
||||
public const MODEL_OAUTH2_ETSY = 'oAuth2Etsy';
|
||||
public const MODEL_OAUTH2_FACEBOOK = 'oAuth2Facebook';
|
||||
public const MODEL_OAUTH2_TRADESHIFT = 'oAuth2Tradeshift';
|
||||
public const MODEL_OAUTH2_PAYPAL = 'oAuth2Paypal';
|
||||
public const MODEL_OAUTH2_GITLAB = 'oAuth2Gitlab';
|
||||
public const MODEL_OAUTH2_AUTHENTIK = 'oAuth2Authentik';
|
||||
public const MODEL_OAUTH2_AUTH0 = 'oAuth2Auth0';
|
||||
public const MODEL_OAUTH2_FUSIONAUTH = 'oAuth2FusionAuth';
|
||||
public const MODEL_OAUTH2_KEYCLOAK = 'oAuth2Keycloak';
|
||||
public const MODEL_OAUTH2_OIDC = 'oAuth2Oidc';
|
||||
public const MODEL_OAUTH2_APPLE = 'oAuth2Apple';
|
||||
public const MODEL_OAUTH2_OKTA = 'oAuth2Okta';
|
||||
public const MODEL_OAUTH2_KICK = 'oAuth2Kick';
|
||||
public const MODEL_OAUTH2_MICROSOFT = 'oAuth2Microsoft';
|
||||
public const MODEL_OAUTH2_PROVIDER_LIST = 'oAuth2ProviderList';
|
||||
|
||||
// Health
|
||||
public const MODEL_HEALTH_STATUS = 'healthStatus';
|
||||
@@ -290,6 +331,9 @@ class Response extends SwooleResponse
|
||||
|
||||
// Console
|
||||
public const MODEL_CONSOLE_VARIABLES = 'consoleVariables';
|
||||
public const MODEL_CONSOLE_OAUTH2_PROVIDER_PARAMETER = 'consoleOAuth2ProviderParameter';
|
||||
public const MODEL_CONSOLE_OAUTH2_PROVIDER = 'consoleOAuth2Provider';
|
||||
public const MODEL_CONSOLE_OAUTH2_PROVIDER_LIST = 'consoleOAuth2ProviderList';
|
||||
|
||||
// Deprecated
|
||||
public const MODEL_PERMISSIONS = 'permissions';
|
||||
|
||||
@@ -30,9 +30,9 @@ class AuthProvider extends Model
|
||||
])
|
||||
->addRule('secret', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'OAuth 2.0 application secret. Might be JSON string if provider requires extra configuration.',
|
||||
'description' => 'OAuth 2.0 application secret. Might be JSON string if provider requires extra configuration. This property is write-only and always returned empty.',
|
||||
'default' => '',
|
||||
'example' => 'Bpw_g9c2TGXxfgLshDbSaL8tsCcqgczQ',
|
||||
'example' => '',
|
||||
])
|
||||
->addRule('enabled', [
|
||||
'type' => self::TYPE_BOOLEAN,
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\Response\Model;
|
||||
|
||||
class ConsoleOAuth2Provider extends Model
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this
|
||||
->addRule('$id', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'OAuth2 provider ID.',
|
||||
'default' => '',
|
||||
'example' => 'github',
|
||||
])
|
||||
->addRule('parameters', [
|
||||
'type' => Response::MODEL_CONSOLE_OAUTH2_PROVIDER_PARAMETER,
|
||||
'description' => 'List of parameters required to configure this OAuth2 provider.',
|
||||
'default' => [],
|
||||
'array' => true,
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return 'Console OAuth2 Provider';
|
||||
}
|
||||
|
||||
public function getType(): string
|
||||
{
|
||||
return Response::MODEL_CONSOLE_OAUTH2_PROVIDER;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\Response\Model;
|
||||
|
||||
class ConsoleOAuth2ProviderList extends Model
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this
|
||||
->addRule('total', [
|
||||
'type' => self::TYPE_INTEGER,
|
||||
'description' => 'Total number of OAuth2 providers exposed by the server.',
|
||||
'default' => 0,
|
||||
'example' => 5,
|
||||
])
|
||||
->addRule('oAuth2Providers', [
|
||||
'type' => Response::MODEL_CONSOLE_OAUTH2_PROVIDER,
|
||||
'description' => 'List of OAuth2 providers, each with the parameters required to configure it.',
|
||||
'default' => [],
|
||||
'array' => true,
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return 'Console OAuth2 Providers List';
|
||||
}
|
||||
|
||||
public function getType(): string
|
||||
{
|
||||
return Response::MODEL_CONSOLE_OAUTH2_PROVIDER_LIST;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\Response\Model;
|
||||
|
||||
class ConsoleOAuth2ProviderParameter extends Model
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this
|
||||
->addRule('$id', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Parameter ID. Maps to the request body field used by the project OAuth2 update endpoint (e.g. `clientId`, `appKey`, `tenant`).',
|
||||
'default' => '',
|
||||
'example' => 'clientId',
|
||||
])
|
||||
->addRule('name', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Verbose, user-facing parameter name as shown in the provider\'s own dashboard. Includes alternate names when the provider exposes more than one.',
|
||||
'default' => '',
|
||||
'example' => 'Client ID or App ID',
|
||||
])
|
||||
->addRule('example', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Example value for this parameter.',
|
||||
'default' => '',
|
||||
'example' => 'e4d87900000000540733',
|
||||
])
|
||||
->addRule('hint', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Optional hint for this parameter, typically calling out a common wrong value. Empty string when no hint is set.',
|
||||
'default' => '',
|
||||
'example' => 'Example of wrong value: 370006',
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return 'Console OAuth2 Provider Parameter';
|
||||
}
|
||||
|
||||
public function getType(): string
|
||||
{
|
||||
return Response::MODEL_CONSOLE_OAUTH2_PROVIDER_PARAMETER;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
|
||||
class OAuth2Amazon extends OAuth2Base
|
||||
{
|
||||
public array $conditions = [
|
||||
'$id' => 'amazon',
|
||||
];
|
||||
|
||||
public function getProviderLabel(): string
|
||||
{
|
||||
return 'Amazon';
|
||||
}
|
||||
|
||||
public function getClientIdExample(): string
|
||||
{
|
||||
return 'amzn1.application-oa2-client.87400c00000000000000000000063d5b2';
|
||||
}
|
||||
|
||||
public function getClientSecretExample(): string
|
||||
{
|
||||
return '79ffe4000000000000000000000000000000000000000000000000000002de55';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'OAuth2Amazon';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_AMAZON;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
|
||||
class OAuth2Apple extends OAuth2Base
|
||||
{
|
||||
public array $conditions = [
|
||||
'$id' => 'apple',
|
||||
];
|
||||
|
||||
public function getProviderLabel(): string
|
||||
{
|
||||
return 'Apple';
|
||||
}
|
||||
|
||||
public function getClientIdExample(): string
|
||||
{
|
||||
return 'ip.appwrite.app.web';
|
||||
}
|
||||
|
||||
public function getClientSecretExample(): string
|
||||
{
|
||||
// Unused: this model overrides __construct() to expose keyId, teamId
|
||||
// and p8File instead of a single clientSecret field.
|
||||
return '';
|
||||
}
|
||||
|
||||
public function getClientIdFieldName(): string
|
||||
{
|
||||
return 'serviceId';
|
||||
}
|
||||
|
||||
public function getClientIdLabel(): string
|
||||
{
|
||||
return 'service ID';
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
// Apple's OAuth2 app credential is split into three fields (.p8 file
|
||||
// contents, Key ID, Team ID) instead of a single clientSecret, so the
|
||||
// rules are defined manually rather than delegating to OAuth2Base.
|
||||
$this
|
||||
->addRule('$id', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'OAuth2 provider ID.',
|
||||
'default' => '',
|
||||
'example' => 'apple',
|
||||
])
|
||||
->addRule('enabled', [
|
||||
'type' => self::TYPE_BOOLEAN,
|
||||
'description' => 'OAuth2 provider is active and can be used to create sessions.',
|
||||
'default' => false,
|
||||
'example' => false,
|
||||
])
|
||||
->addRule($this->getClientIdFieldName(), [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => $this->getClientIdDescription(),
|
||||
'default' => '',
|
||||
'example' => $this->getClientIdExample(),
|
||||
])
|
||||
->addRule('keyId', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Apple OAuth2 key ID.',
|
||||
'default' => '',
|
||||
'example' => 'P4000000N8',
|
||||
])
|
||||
->addRule('teamId', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Apple OAuth2 team ID.',
|
||||
'default' => '',
|
||||
'example' => 'D4000000R6',
|
||||
])
|
||||
->addRule('p8File', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Apple OAuth2 .p8 private key file contents. The secret key wrapped by the PEM markers is 200 characters long.',
|
||||
'default' => '',
|
||||
'example' => '-----BEGIN PRIVATE KEY-----MIGTAg...jy2Xbna-----END PRIVATE KEY-----',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'OAuth2Apple';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_APPLE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
|
||||
class OAuth2Auth0 extends OAuth2Base
|
||||
{
|
||||
public array $conditions = [
|
||||
'$id' => 'auth0',
|
||||
];
|
||||
|
||||
public function getProviderLabel(): string
|
||||
{
|
||||
return 'Auth0';
|
||||
}
|
||||
|
||||
public function getClientIdExample(): string
|
||||
{
|
||||
return 'OaOkIA000000000000000000005KLSYq';
|
||||
}
|
||||
|
||||
public function getClientSecretExample(): string
|
||||
{
|
||||
return 'zXz0000-00000000000000000000000000000-00000000000000000000PJafnF';
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->addRule('endpoint', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Auth0 OAuth2 endpoint domain.',
|
||||
'default' => '',
|
||||
'example' => 'example.us.auth0.com',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'OAuth2Auth0';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_AUTH0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
|
||||
class OAuth2Authentik extends OAuth2Base
|
||||
{
|
||||
public array $conditions = [
|
||||
'$id' => 'authentik',
|
||||
];
|
||||
|
||||
public function getProviderLabel(): string
|
||||
{
|
||||
return 'Authentik';
|
||||
}
|
||||
|
||||
public function getClientIdExample(): string
|
||||
{
|
||||
return 'dTKOPa0000000000000000000000000000e7G8hv';
|
||||
}
|
||||
|
||||
public function getClientSecretExample(): string
|
||||
{
|
||||
return 'ntQadq000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000Hp5WK';
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->addRule('endpoint', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Authentik OAuth2 endpoint domain.',
|
||||
'default' => '',
|
||||
'example' => 'example.authentik.com',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'OAuth2Authentik';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_AUTHENTIK;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
|
||||
class OAuth2Autodesk extends OAuth2Base
|
||||
{
|
||||
public array $conditions = [
|
||||
'$id' => 'autodesk',
|
||||
];
|
||||
|
||||
public function getProviderLabel(): string
|
||||
{
|
||||
return 'Autodesk';
|
||||
}
|
||||
|
||||
public function getClientIdExample(): string
|
||||
{
|
||||
return '5zw90v00000000000000000000kVYXN7';
|
||||
}
|
||||
|
||||
public function getClientSecretExample(): string
|
||||
{
|
||||
return '7I000000000000MW';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'OAuth2Autodesk';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_AUTODESK;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response\Model;
|
||||
|
||||
abstract class OAuth2Base extends Model
|
||||
{
|
||||
/**
|
||||
* Provider display label used in rule descriptions.
|
||||
*
|
||||
* @return string e.g. 'GitHub', 'Discord', 'Dropbox'
|
||||
*/
|
||||
abstract public function getProviderLabel(): string;
|
||||
|
||||
/**
|
||||
* Example value for the client ID rule.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract public function getClientIdExample(): string;
|
||||
|
||||
/**
|
||||
* Example value for the client secret rule.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract public function getClientSecretExample(): string;
|
||||
|
||||
/**
|
||||
* Public-facing field name of the client ID. Providers may override when
|
||||
* they use different terminology (e.g. Dropbox -> 'appKey').
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getClientIdFieldName(): string
|
||||
{
|
||||
return 'clientId';
|
||||
}
|
||||
|
||||
/**
|
||||
* Public-facing field name of the client secret. Providers may override
|
||||
* when they use different terminology (e.g. Dropbox -> 'appSecret').
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getClientSecretFieldName(): string
|
||||
{
|
||||
return 'clientSecret';
|
||||
}
|
||||
|
||||
/**
|
||||
* Human-readable label for the client ID, used in the generated rule
|
||||
* description. Providers may override (e.g. Dropbox -> 'app key').
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getClientIdLabel(): string
|
||||
{
|
||||
return 'client ID';
|
||||
}
|
||||
|
||||
/**
|
||||
* Human-readable label for the client secret, used in the generated rule
|
||||
* description. Providers may override (e.g. Dropbox -> 'app secret').
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getClientSecretLabel(): string
|
||||
{
|
||||
return 'client secret';
|
||||
}
|
||||
|
||||
/**
|
||||
* Rule description for the client ID. Auto-generated from the provider
|
||||
* label and client ID label. Providers may override to add extra context.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getClientIdDescription(): string
|
||||
{
|
||||
return $this->getProviderLabel() . ' OAuth2 ' . $this->getClientIdLabel() . '.';
|
||||
}
|
||||
|
||||
/**
|
||||
* Rule description for the client secret. Auto-generated from the provider
|
||||
* label and client secret label. Providers may override to add extra
|
||||
* context.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getClientSecretDescription(): string
|
||||
{
|
||||
return $this->getProviderLabel() . ' OAuth2 ' . $this->getClientSecretLabel() . '.';
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this
|
||||
->addRule('$id', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'OAuth2 provider ID.',
|
||||
'default' => '',
|
||||
'example' => 'github',
|
||||
])
|
||||
->addRule('enabled', [
|
||||
'type' => self::TYPE_BOOLEAN,
|
||||
'description' => 'OAuth2 provider is active and can be used to create sessions.',
|
||||
'default' => false,
|
||||
'example' => false,
|
||||
])
|
||||
->addRule($this->getClientIdFieldName(), [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => $this->getClientIdDescription(),
|
||||
'default' => '',
|
||||
'example' => $this->getClientIdExample(),
|
||||
])
|
||||
->addRule($this->getClientSecretFieldName(), [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => $this->getClientSecretDescription(),
|
||||
'default' => '',
|
||||
'example' => $this->getClientSecretExample(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
|
||||
class OAuth2Bitbucket extends OAuth2Base
|
||||
{
|
||||
public array $conditions = [
|
||||
'$id' => 'bitbucket',
|
||||
];
|
||||
|
||||
public function getProviderLabel(): string
|
||||
{
|
||||
return 'Bitbucket';
|
||||
}
|
||||
|
||||
public function getClientIdExample(): string
|
||||
{
|
||||
return 'Knt70000000000ByRc';
|
||||
}
|
||||
|
||||
public function getClientSecretExample(): string
|
||||
{
|
||||
return 'NMfLZJ00000000000000000000TLQdDx';
|
||||
}
|
||||
|
||||
public function getClientIdFieldName(): string
|
||||
{
|
||||
return 'key';
|
||||
}
|
||||
|
||||
public function getClientSecretFieldName(): string
|
||||
{
|
||||
return 'secret';
|
||||
}
|
||||
|
||||
public function getClientIdLabel(): string
|
||||
{
|
||||
return 'key';
|
||||
}
|
||||
|
||||
public function getClientSecretLabel(): string
|
||||
{
|
||||
return 'secret';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'OAuth2Bitbucket';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_BITBUCKET;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
|
||||
class OAuth2Bitly extends OAuth2Base
|
||||
{
|
||||
public array $conditions = [
|
||||
'$id' => 'bitly',
|
||||
];
|
||||
|
||||
public function getProviderLabel(): string
|
||||
{
|
||||
return 'Bitly';
|
||||
}
|
||||
|
||||
public function getClientIdExample(): string
|
||||
{
|
||||
return 'd95151000000000000000000000000000067af9b';
|
||||
}
|
||||
|
||||
public function getClientSecretExample(): string
|
||||
{
|
||||
return 'a13e250000000000000000000000000000d73095';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'OAuth2Bitly';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_BITLY;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
|
||||
class OAuth2Box extends OAuth2Base
|
||||
{
|
||||
public array $conditions = [
|
||||
'$id' => 'box',
|
||||
];
|
||||
|
||||
public function getProviderLabel(): string
|
||||
{
|
||||
return 'Box';
|
||||
}
|
||||
|
||||
public function getClientIdExample(): string
|
||||
{
|
||||
return 'deglcs00000000000000000000x2og6y';
|
||||
}
|
||||
|
||||
public function getClientSecretExample(): string
|
||||
{
|
||||
return 'OKM1f100000000000000000000eshEif';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'OAuth2Box';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_BOX;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
|
||||
class OAuth2Dailymotion extends OAuth2Base
|
||||
{
|
||||
public array $conditions = [
|
||||
'$id' => 'dailymotion',
|
||||
];
|
||||
|
||||
public function getProviderLabel(): string
|
||||
{
|
||||
return 'Dailymotion';
|
||||
}
|
||||
|
||||
public function getClientIdExample(): string
|
||||
{
|
||||
return '07a9000000000000067f';
|
||||
}
|
||||
|
||||
public function getClientSecretExample(): string
|
||||
{
|
||||
return 'a399a90000000000000000000000000000d90639';
|
||||
}
|
||||
|
||||
public function getClientIdFieldName(): string
|
||||
{
|
||||
return 'apiKey';
|
||||
}
|
||||
|
||||
public function getClientSecretFieldName(): string
|
||||
{
|
||||
return 'apiSecret';
|
||||
}
|
||||
|
||||
public function getClientIdLabel(): string
|
||||
{
|
||||
return 'API key';
|
||||
}
|
||||
|
||||
public function getClientSecretLabel(): string
|
||||
{
|
||||
return 'API secret';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'OAuth2Dailymotion';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_DAILYMOTION;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
|
||||
class OAuth2Discord extends OAuth2Base
|
||||
{
|
||||
public array $conditions = [
|
||||
'$id' => 'discord',
|
||||
];
|
||||
|
||||
public function getProviderLabel(): string
|
||||
{
|
||||
return 'Discord';
|
||||
}
|
||||
|
||||
public function getClientIdExample(): string
|
||||
{
|
||||
return '950722000000343754';
|
||||
}
|
||||
|
||||
public function getClientSecretExample(): string
|
||||
{
|
||||
return 'YmPXnM000000000000000000002zFg5D';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'OAuth2Discord';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_DISCORD;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
|
||||
class OAuth2Disqus extends OAuth2Base
|
||||
{
|
||||
public array $conditions = [
|
||||
'$id' => 'disqus',
|
||||
];
|
||||
|
||||
public function getProviderLabel(): string
|
||||
{
|
||||
return 'Disqus';
|
||||
}
|
||||
|
||||
public function getClientIdExample(): string
|
||||
{
|
||||
return 'cgegH70000000000000000000000000000000000000000000000000000Hr1nYX';
|
||||
}
|
||||
|
||||
public function getClientSecretExample(): string
|
||||
{
|
||||
return 'W7Bykj00000000000000000000000000000000000000000000000000003o43w9';
|
||||
}
|
||||
|
||||
public function getClientIdFieldName(): string
|
||||
{
|
||||
return 'publicKey';
|
||||
}
|
||||
|
||||
public function getClientSecretFieldName(): string
|
||||
{
|
||||
return 'secretKey';
|
||||
}
|
||||
|
||||
public function getClientIdLabel(): string
|
||||
{
|
||||
return 'public key';
|
||||
}
|
||||
|
||||
public function getClientSecretLabel(): string
|
||||
{
|
||||
return 'secret key';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'OAuth2Disqus';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_DISQUS;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
|
||||
class OAuth2Dropbox extends OAuth2Base
|
||||
{
|
||||
public array $conditions = [
|
||||
'$id' => 'dropbox',
|
||||
];
|
||||
|
||||
public function getProviderLabel(): string
|
||||
{
|
||||
return 'Dropbox';
|
||||
}
|
||||
|
||||
public function getClientIdExample(): string
|
||||
{
|
||||
return 'jl000000000009t';
|
||||
}
|
||||
|
||||
public function getClientSecretExample(): string
|
||||
{
|
||||
return 'g200000000000vw';
|
||||
}
|
||||
|
||||
public function getClientIdFieldName(): string
|
||||
{
|
||||
return 'appKey';
|
||||
}
|
||||
|
||||
public function getClientSecretFieldName(): string
|
||||
{
|
||||
return 'appSecret';
|
||||
}
|
||||
|
||||
public function getClientIdLabel(): string
|
||||
{
|
||||
return 'app key';
|
||||
}
|
||||
|
||||
public function getClientSecretLabel(): string
|
||||
{
|
||||
return 'app secret';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'OAuth2Dropbox';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_DROPBOX;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
|
||||
class OAuth2Etsy extends OAuth2Base
|
||||
{
|
||||
public array $conditions = [
|
||||
'$id' => 'etsy',
|
||||
];
|
||||
|
||||
public function getProviderLabel(): string
|
||||
{
|
||||
return 'Etsy';
|
||||
}
|
||||
|
||||
public function getClientIdExample(): string
|
||||
{
|
||||
return 'nsgzxh0000000000008j85a2';
|
||||
}
|
||||
|
||||
public function getClientSecretExample(): string
|
||||
{
|
||||
return 'tp000000ru';
|
||||
}
|
||||
|
||||
public function getClientIdFieldName(): string
|
||||
{
|
||||
return 'keyString';
|
||||
}
|
||||
|
||||
public function getClientSecretFieldName(): string
|
||||
{
|
||||
return 'sharedSecret';
|
||||
}
|
||||
|
||||
public function getClientIdLabel(): string
|
||||
{
|
||||
return 'keystring';
|
||||
}
|
||||
|
||||
public function getClientSecretLabel(): string
|
||||
{
|
||||
return 'shared secret';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'OAuth2Etsy';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_ETSY;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
|
||||
class OAuth2Facebook extends OAuth2Base
|
||||
{
|
||||
public array $conditions = [
|
||||
'$id' => 'facebook',
|
||||
];
|
||||
|
||||
public function getProviderLabel(): string
|
||||
{
|
||||
return 'Facebook';
|
||||
}
|
||||
|
||||
public function getClientIdExample(): string
|
||||
{
|
||||
return '260600000007694';
|
||||
}
|
||||
|
||||
public function getClientSecretExample(): string
|
||||
{
|
||||
return '2d0b2800000000000000000000d38af4';
|
||||
}
|
||||
|
||||
public function getClientIdFieldName(): string
|
||||
{
|
||||
return 'appId';
|
||||
}
|
||||
|
||||
public function getClientSecretFieldName(): string
|
||||
{
|
||||
return 'appSecret';
|
||||
}
|
||||
|
||||
public function getClientIdLabel(): string
|
||||
{
|
||||
return 'app ID';
|
||||
}
|
||||
|
||||
public function getClientSecretLabel(): string
|
||||
{
|
||||
return 'app secret';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'OAuth2Facebook';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_FACEBOOK;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
|
||||
class OAuth2Figma extends OAuth2Base
|
||||
{
|
||||
public array $conditions = [
|
||||
'$id' => 'figma',
|
||||
];
|
||||
|
||||
public function getProviderLabel(): string
|
||||
{
|
||||
return 'Figma';
|
||||
}
|
||||
|
||||
public function getClientIdExample(): string
|
||||
{
|
||||
return 'byay5H0000000000VtiI40';
|
||||
}
|
||||
|
||||
public function getClientSecretExample(): string
|
||||
{
|
||||
return 'yEpOYn0000000000000000004iIsU5';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'OAuth2Figma';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_FIGMA;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
|
||||
class OAuth2FusionAuth extends OAuth2Base
|
||||
{
|
||||
public array $conditions = [
|
||||
'$id' => 'fusionauth',
|
||||
];
|
||||
|
||||
public function getProviderLabel(): string
|
||||
{
|
||||
return 'FusionAuth';
|
||||
}
|
||||
|
||||
public function getClientIdExample(): string
|
||||
{
|
||||
return 'b2222c00-0000-0000-0000-000000862097';
|
||||
}
|
||||
|
||||
public function getClientSecretExample(): string
|
||||
{
|
||||
return 'Jx4s0C0000000000000000000000000000000wGqLsc';
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->addRule('endpoint', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'FusionAuth OAuth2 endpoint domain.',
|
||||
'default' => '',
|
||||
'example' => 'example.fusionauth.io',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'OAuth2FusionAuth';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_FUSIONAUTH;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
|
||||
class OAuth2GitHub extends OAuth2Base
|
||||
{
|
||||
public array $conditions = [
|
||||
'$id' => 'github',
|
||||
];
|
||||
|
||||
public function getProviderLabel(): string
|
||||
{
|
||||
return 'GitHub';
|
||||
}
|
||||
|
||||
public function getClientIdExample(): string
|
||||
{
|
||||
return 'e4d87900000000540733';
|
||||
}
|
||||
|
||||
public function getClientSecretExample(): string
|
||||
{
|
||||
return '5e07c00000000000000000000000000000198bcc';
|
||||
}
|
||||
|
||||
public function getClientIdDescription(): string
|
||||
{
|
||||
return parent::getClientIdDescription() . ' For GitHub Apps, use the "App ID" when both an App ID and client ID are available.';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'OAuth2GitHub';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_GITHUB;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
|
||||
class OAuth2Gitlab extends OAuth2Base
|
||||
{
|
||||
public array $conditions = [
|
||||
'$id' => 'gitlab',
|
||||
];
|
||||
|
||||
public function getProviderLabel(): string
|
||||
{
|
||||
return 'GitLab';
|
||||
}
|
||||
|
||||
public function getClientIdExample(): string
|
||||
{
|
||||
return 'd41ffe0000000000000000000000000000000000000000000000000000d5e252';
|
||||
}
|
||||
|
||||
public function getClientSecretExample(): string
|
||||
{
|
||||
return 'gloas-838cfa0000000000000000000000000000000000000000000000000000ecbb38';
|
||||
}
|
||||
|
||||
public function getClientIdFieldName(): string
|
||||
{
|
||||
return 'applicationId';
|
||||
}
|
||||
|
||||
public function getClientSecretFieldName(): string
|
||||
{
|
||||
return 'secret';
|
||||
}
|
||||
|
||||
public function getClientIdLabel(): string
|
||||
{
|
||||
return 'application ID';
|
||||
}
|
||||
|
||||
public function getClientSecretLabel(): string
|
||||
{
|
||||
return 'secret';
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->addRule('endpoint', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'GitLab OAuth2 endpoint URL. Defaults to https://gitlab.com for self-hosted instances.',
|
||||
'default' => '',
|
||||
'example' => 'https://gitlab.com',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'OAuth2Gitlab';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_GITLAB;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
|
||||
class OAuth2Google extends OAuth2Base
|
||||
{
|
||||
public array $conditions = [
|
||||
'$id' => 'google',
|
||||
];
|
||||
|
||||
public function getProviderLabel(): string
|
||||
{
|
||||
return 'Google';
|
||||
}
|
||||
|
||||
public function getClientIdExample(): string
|
||||
{
|
||||
return '120000000095-92ifjb00000000000000000000g7ijfb.apps.googleusercontent.com';
|
||||
}
|
||||
|
||||
public function getClientSecretExample(): string
|
||||
{
|
||||
return 'GOCSPX-2k8gsR0000000000000000VNahJj';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'OAuth2Google';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_GOOGLE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
|
||||
class OAuth2Keycloak extends OAuth2Base
|
||||
{
|
||||
public array $conditions = [
|
||||
'$id' => 'keycloak',
|
||||
];
|
||||
|
||||
public function getProviderLabel(): string
|
||||
{
|
||||
return 'Keycloak';
|
||||
}
|
||||
|
||||
public function getClientIdExample(): string
|
||||
{
|
||||
return 'appwrite-o0000000st-app';
|
||||
}
|
||||
|
||||
public function getClientSecretExample(): string
|
||||
{
|
||||
return 'jdjrJd00000000000000000000HUsaZO';
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->addRule('endpoint', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Keycloak OAuth2 endpoint domain.',
|
||||
'default' => '',
|
||||
'example' => 'keycloak.example.com',
|
||||
]);
|
||||
|
||||
$this->addRule('realmName', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Keycloak OAuth2 realm name.',
|
||||
'default' => '',
|
||||
'example' => 'appwrite-realm',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'OAuth2Keycloak';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_KEYCLOAK;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
|
||||
class OAuth2Kick extends OAuth2Base
|
||||
{
|
||||
public array $conditions = [
|
||||
'$id' => 'kick',
|
||||
];
|
||||
|
||||
public function getProviderLabel(): string
|
||||
{
|
||||
return 'Kick';
|
||||
}
|
||||
|
||||
public function getClientIdExample(): string
|
||||
{
|
||||
return '01KQ7C00000000000001MFHS32';
|
||||
}
|
||||
|
||||
public function getClientSecretExample(): string
|
||||
{
|
||||
return '34ac5600000000000000000000000000000000000000000000000000e830c8b';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'OAuth2Kick';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_KICK;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
|
||||
class OAuth2Linkedin extends OAuth2Base
|
||||
{
|
||||
public array $conditions = [
|
||||
'$id' => 'linkedin',
|
||||
];
|
||||
|
||||
public function getProviderLabel(): string
|
||||
{
|
||||
return 'LinkedIn';
|
||||
}
|
||||
|
||||
public function getClientIdExample(): string
|
||||
{
|
||||
return '770000000000dv';
|
||||
}
|
||||
|
||||
public function getClientSecretExample(): string
|
||||
{
|
||||
return 'WPL_AP1.2Bf0000000000000./HtlYw==';
|
||||
}
|
||||
|
||||
public function getClientSecretFieldName(): string
|
||||
{
|
||||
return 'primaryClientSecret';
|
||||
}
|
||||
|
||||
public function getClientSecretLabel(): string
|
||||
{
|
||||
return 'primary client secret';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'OAuth2Linkedin';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_LINKEDIN;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
|
||||
class OAuth2Microsoft extends OAuth2Base
|
||||
{
|
||||
public array $conditions = [
|
||||
'$id' => 'microsoft',
|
||||
];
|
||||
|
||||
public function getProviderLabel(): string
|
||||
{
|
||||
return 'Microsoft';
|
||||
}
|
||||
|
||||
public function getClientIdExample(): string
|
||||
{
|
||||
return '00001111-aaaa-2222-bbbb-3333cccc4444';
|
||||
}
|
||||
|
||||
public function getClientSecretExample(): string
|
||||
{
|
||||
return 'A1bC2dE3fH4iJ5kL6mN7oP8qR9sT0u';
|
||||
}
|
||||
|
||||
public function getClientIdFieldName(): string
|
||||
{
|
||||
return 'applicationId';
|
||||
}
|
||||
|
||||
public function getClientSecretFieldName(): string
|
||||
{
|
||||
return 'applicationSecret';
|
||||
}
|
||||
|
||||
public function getClientIdLabel(): string
|
||||
{
|
||||
return 'application ID';
|
||||
}
|
||||
|
||||
public function getClientSecretLabel(): string
|
||||
{
|
||||
return 'application secret';
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->addRule('tenant', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Microsoft Entra ID tenant identifier. Use \'common\', \'organizations\', \'consumers\' or a specific tenant ID.',
|
||||
'default' => '',
|
||||
'example' => 'common',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'OAuth2Microsoft';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_MICROSOFT;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
|
||||
class OAuth2Notion extends OAuth2Base
|
||||
{
|
||||
public array $conditions = [
|
||||
'$id' => 'notion',
|
||||
];
|
||||
|
||||
public function getProviderLabel(): string
|
||||
{
|
||||
return 'Notion';
|
||||
}
|
||||
|
||||
public function getClientIdExample(): string
|
||||
{
|
||||
return '341d8700-0000-0000-0000-000000446ee3';
|
||||
}
|
||||
|
||||
public function getClientSecretExample(): string
|
||||
{
|
||||
return 'secret_dLUr4b000000000000000000000000000000lFHAa9';
|
||||
}
|
||||
|
||||
public function getClientIdFieldName(): string
|
||||
{
|
||||
return 'oauthClientId';
|
||||
}
|
||||
|
||||
public function getClientSecretFieldName(): string
|
||||
{
|
||||
return 'oauthClientSecret';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'OAuth2Notion';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_NOTION;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
|
||||
class OAuth2Oidc extends OAuth2Base
|
||||
{
|
||||
public array $conditions = [
|
||||
'$id' => 'oidc',
|
||||
];
|
||||
|
||||
public function getProviderLabel(): string
|
||||
{
|
||||
return 'OpenID Connect';
|
||||
}
|
||||
|
||||
public function getClientIdExample(): string
|
||||
{
|
||||
return 'qibI2x0000000000000000000000000006L2YFoG';
|
||||
}
|
||||
|
||||
public function getClientSecretExample(): string
|
||||
{
|
||||
return 'Ah68ed000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003qpcHV';
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this
|
||||
->addRule('wellKnownURL', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'OpenID Connect well-known configuration URL. When set, authorization, token, and user info endpoints can be discovered automatically.',
|
||||
'default' => '',
|
||||
'example' => 'https://myoauth.com/.well-known/openid-configuration',
|
||||
])
|
||||
->addRule('authorizationURL', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'OpenID Connect authorization endpoint URL.',
|
||||
'default' => '',
|
||||
'example' => 'https://myoauth.com/oauth2/authorize',
|
||||
])
|
||||
->addRule('tokenUrl', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'OpenID Connect token endpoint URL.',
|
||||
'default' => '',
|
||||
'example' => 'https://myoauth.com/oauth2/token',
|
||||
])
|
||||
->addRule('userInfoUrl', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'OpenID Connect user info endpoint URL.',
|
||||
'default' => '',
|
||||
'example' => 'https://myoauth.com/oauth2/userinfo',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'OAuth2Oidc';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_OIDC;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
|
||||
class OAuth2Okta extends OAuth2Base
|
||||
{
|
||||
public array $conditions = [
|
||||
'$id' => 'okta',
|
||||
];
|
||||
|
||||
public function getProviderLabel(): string
|
||||
{
|
||||
return 'Okta';
|
||||
}
|
||||
|
||||
public function getClientIdExample(): string
|
||||
{
|
||||
return '0oa00000000000000698';
|
||||
}
|
||||
|
||||
public function getClientSecretExample(): string
|
||||
{
|
||||
return 'Kiq0000000000000000000000000000000000000-00000000000H2L5-3SJ-vRV';
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->addRule('domain', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Okta OAuth2 domain.',
|
||||
'default' => '',
|
||||
'example' => 'trial-6400025.okta.com',
|
||||
]);
|
||||
|
||||
$this->addRule('authorizationServerId', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Okta OAuth2 authorization server ID.',
|
||||
'default' => '',
|
||||
'example' => 'aus000000000000000h7z',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'OAuth2Okta';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_OKTA;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
|
||||
class OAuth2Paypal extends OAuth2Base
|
||||
{
|
||||
public array $conditions = [
|
||||
'$id' => ['paypal', 'paypalSandbox'],
|
||||
];
|
||||
|
||||
public function getProviderLabel(): string
|
||||
{
|
||||
return 'PayPal';
|
||||
}
|
||||
|
||||
public function getClientIdExample(): string
|
||||
{
|
||||
return 'AdhIEG7-000000000000-0000000000000000000000000000000-0000000000000000000000-2pyB';
|
||||
}
|
||||
|
||||
public function getClientSecretExample(): string
|
||||
{
|
||||
return 'EH8KCXtew--000000000000000000000000000000000000000_C-1_5UP_000000000000000CB7KDp';
|
||||
}
|
||||
|
||||
public function getClientSecretFieldName(): string
|
||||
{
|
||||
return 'secretKey';
|
||||
}
|
||||
|
||||
public function getClientSecretLabel(): string
|
||||
{
|
||||
return 'secret key';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'OAuth2Paypal';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_PAYPAL;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
|
||||
class OAuth2Podio extends OAuth2Base
|
||||
{
|
||||
public array $conditions = [
|
||||
'$id' => 'podio',
|
||||
];
|
||||
|
||||
public function getProviderLabel(): string
|
||||
{
|
||||
return 'Podio';
|
||||
}
|
||||
|
||||
public function getClientIdExample(): string
|
||||
{
|
||||
return 'appwrite-oauth-test-app';
|
||||
}
|
||||
|
||||
public function getClientSecretExample(): string
|
||||
{
|
||||
return 'Rn247T0000000000000000000000000000000000000000000000000000W2zWTN';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'OAuth2Podio';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_PODIO;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\Response\Model;
|
||||
|
||||
class OAuth2ProviderList extends Model
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this
|
||||
->addRule('total', [
|
||||
'type' => self::TYPE_INTEGER,
|
||||
'description' => 'Total number of OAuth2 providers in the given project.',
|
||||
'default' => 0,
|
||||
'example' => 5,
|
||||
])
|
||||
->addRule('providers', [
|
||||
'type' => [
|
||||
Response::MODEL_OAUTH2_GITHUB,
|
||||
Response::MODEL_OAUTH2_DISCORD,
|
||||
Response::MODEL_OAUTH2_FIGMA,
|
||||
Response::MODEL_OAUTH2_DROPBOX,
|
||||
Response::MODEL_OAUTH2_DAILYMOTION,
|
||||
Response::MODEL_OAUTH2_BITBUCKET,
|
||||
Response::MODEL_OAUTH2_BITLY,
|
||||
Response::MODEL_OAUTH2_BOX,
|
||||
Response::MODEL_OAUTH2_AUTODESK,
|
||||
Response::MODEL_OAUTH2_GOOGLE,
|
||||
Response::MODEL_OAUTH2_ZOOM,
|
||||
Response::MODEL_OAUTH2_ZOHO,
|
||||
Response::MODEL_OAUTH2_YANDEX,
|
||||
Response::MODEL_OAUTH2_X,
|
||||
Response::MODEL_OAUTH2_WORDPRESS,
|
||||
Response::MODEL_OAUTH2_TWITCH,
|
||||
Response::MODEL_OAUTH2_STRIPE,
|
||||
Response::MODEL_OAUTH2_SPOTIFY,
|
||||
Response::MODEL_OAUTH2_SLACK,
|
||||
Response::MODEL_OAUTH2_PODIO,
|
||||
Response::MODEL_OAUTH2_NOTION,
|
||||
Response::MODEL_OAUTH2_SALESFORCE,
|
||||
Response::MODEL_OAUTH2_YAHOO,
|
||||
Response::MODEL_OAUTH2_LINKEDIN,
|
||||
Response::MODEL_OAUTH2_DISQUS,
|
||||
Response::MODEL_OAUTH2_AMAZON,
|
||||
Response::MODEL_OAUTH2_ETSY,
|
||||
Response::MODEL_OAUTH2_FACEBOOK,
|
||||
Response::MODEL_OAUTH2_TRADESHIFT,
|
||||
Response::MODEL_OAUTH2_PAYPAL,
|
||||
Response::MODEL_OAUTH2_GITLAB,
|
||||
Response::MODEL_OAUTH2_AUTHENTIK,
|
||||
Response::MODEL_OAUTH2_AUTH0,
|
||||
Response::MODEL_OAUTH2_FUSIONAUTH,
|
||||
Response::MODEL_OAUTH2_KEYCLOAK,
|
||||
Response::MODEL_OAUTH2_OIDC,
|
||||
Response::MODEL_OAUTH2_APPLE,
|
||||
Response::MODEL_OAUTH2_OKTA,
|
||||
Response::MODEL_OAUTH2_KICK,
|
||||
Response::MODEL_OAUTH2_MICROSOFT,
|
||||
],
|
||||
'description' => 'List of OAuth2 providers.',
|
||||
'default' => [],
|
||||
'array' => true,
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return 'OAuth2 Providers List';
|
||||
}
|
||||
|
||||
public function getType(): string
|
||||
{
|
||||
return Response::MODEL_OAUTH2_PROVIDER_LIST;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user