Add Discord OAuth endpoint

This commit is contained in:
Matej Bačo
2026-04-24 11:35:30 +02:00
parent 93f7a0d902
commit 36435d940d
6 changed files with 201 additions and 0 deletions
+5
View File
@@ -1,6 +1,7 @@
<?php
namespace Appwrite\Auth\OAuth2;
use Utopia\Fetch\Client as FetchClient;
use Appwrite\Auth\OAuth2;
@@ -183,4 +184,8 @@ class Discord extends OAuth2
return $this->user;
}
public function verifyCredentials(): void {
// TODO: Implement, eventuelly. Refer to GitHub.php in this directory for inspiration
}
}
@@ -0,0 +1,144 @@
<?php
namespace Appwrite\Platform\Modules\Project\Http\Project\OAuth2\Discord;
use Appwrite\Auth\OAuth2\Discord;
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\ArrayList;
use Utopia\Validator\Boolean;
use Utopia\Validator\Nullable;
use Utopia\Validator\Text;
class Update extends Action
{
use HTTP;
public static function getName()
{
return 'updateProjectOAuth2Discord';
}
public static function getProviderId(): string
{
return 'discord';
}
/**
* @return class-string
*/
public static function getProviderClass(): string
{
return Discord::class;
}
public function __construct()
{
$this
->setHttpMethod(Action::HTTP_REQUEST_METHOD_PATCH)
->setHttpPath('/v1/project/oauth2/discord')
->desc('Update project OAuth2 Discord')
->groups(['api', 'project'])
->label('scope', 'oauth2.write')
->label('event', 'oauth2.discord.update')
->label('audits.event', 'project.oauth2.discord.update')
->label('audits.resource', 'project.oauth2/{response.$id}')
->label('sdk', new Method(
namespace: 'project',
group: 'oauth2',
name: 'updateOAuth2Discord',
description: <<<EOT
Update the project OAuth2 Discord configuration.
EOT,
auth: [AuthType::ADMIN, AuthType::KEY],
responses: [
new SDKResponse(
code: Response::STATUS_CODE_OK,
model: Response::MODEL_OAUTH2_DISCORD,
)
],
))
->param('clientId', null, new Nullable(new Text(256, 0)), 'Client ID of Discord OAuth2 app. For example: 950722000000343754', optional: true)
->param('clientSecret', null, new Nullable(new Text(512, 0)), 'Client Secret of Discord OAuth2 app. For example: YmPXnM000000000000000000002zFg5D', 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')
->callback($this->action(...));
}
public function action(
?string $clientId,
?string $clientSecret,
?bool $enabled,
Response $response,
Database $dbForPlatform,
Document $project,
Authorization $authorization
): void {
$providerId = self::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 = self::getProviderClass();
$providerInstance = new $providerClass(appId: $oAuthProviders[$appIdKey], appSecret: $oAuthProviders[$appSecretKey], callback: '', state: [], scopes: []);
$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
]);
$project = $authorization->skip(fn() => $dbForPlatform->updateDocument('projects', $project->getId(), $updates));
$response->dynamic(new Document([
'$id' => $providerId,
'enabled' => $oAuthProviders[$enabledKey] ?? false,
'clientId' => $oAuthProviders[$appIdKey] ?? '',
'clientSecret' => $oAuthProviders[$appSecretKey] ?? '',
]), Response::MODEL_OAUTH2_DISCORD);
}
}
@@ -16,6 +16,7 @@ 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\Discord\Update as UpdateOAuth2Discord;
use Appwrite\Platform\Modules\Project\Http\Project\Platforms\Android\Create as CreateAndroidPlatform;
use Appwrite\Platform\Modules\Project\Http\Project\OAuth2\GitHub\Update as UpdateOAuth2GitHub;
use Appwrite\Platform\Modules\Project\Http\Project\Platforms\Android\Update as UpdateAndroidPlatform;
@@ -133,5 +134,6 @@ class Http extends Service
// OAuth2
$this->addAction(UpdateOAuth2GitHub::getName(), new UpdateOAuth2GitHub());
$this->addAction(UpdateOAuth2Discord::getName(), new UpdateOAuth2Discord());
}
}
+1
View File
@@ -279,6 +279,7 @@ class Response extends SwooleResponse
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';
// Health
public const MODEL_HEALTH_STATUS = 'healthStatus';
@@ -0,0 +1,47 @@
<?php
namespace Appwrite\Utopia\Response\Model;
use Appwrite\Utopia\Response;
class OAuth2Discord extends OAuth2Base
{
public function __construct()
{
parent::__construct();
$this
->addRule('clientId', [
'type' => self::TYPE_STRING,
'description' => 'Discord OAuth 2 client ID.',
'default' => '',
'example' => '950722000000343754',
])
->addRule('clientSecret', [
'type' => self::TYPE_STRING,
'description' => 'Discord OAuth 2 client secret.',
'default' => '',
'example' => 'YmPXnM000000000000000000002zFg5D',
]);
}
/**
* Get Name
*
* @return string
*/
public function getName(): string
{
return 'OAuth2Discord';
}
/**
* Get Type
*
* @return string
*/
public function getType(): string
{
return Response::MODEL_OAUTH2_DISCORD;
}
}