Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OAuth improvements #903

Merged
merged 10 commits into from
Jan 15, 2025
65 changes: 65 additions & 0 deletions app/Extensions/OAuth/Providers/AuthentikProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?php

namespace App\Extensions\OAuth\Providers;

use Filament\Forms\Components\TextInput;
use SocialiteProviders\Authentik\Provider;

final class AuthentikProvider extends OAuthProvider
{
public function getId(): string
{
return 'authentik';
}

public function getProviderClass(): string
{
return Provider::class;
}

public function getServiceConfig(): array
{
return [
'client_id' => null,
'client_secret' => env('OAUTH_STEAM_CLIENT_SECRET'),
'allowed_hosts' => [
str_replace(['http://', 'https://'], '', env('APP_URL')),
],
];
}

public function getSettingsForm(): array
{
return array_merge(parent::getSettingsForm(), [
TextInput::make('OAUTH_AUTHENTIK_BASE_URL')
->label('Base URL')
->placeholder('Base URL')
->columnSpan(2)
->required()
->url()
->autocomplete(false)
->default(env('OAUTH_AUTHENTIK_BASE_URL')),
TextInput::make('OAUTH_AUTHENTIK_DISPLAY_NAME')
->label('Display Name')
->placeholder('Display Name')
->columnSpan(2)
->autocomplete(false)
->default(env('OAUTH_AUTHENTIK_DISPLAY_NAME', 'Authentik')),
]);
}

public function getName(): string
{
return env('OAUTH_AUTHENTIK_DISPLAY_NAME') ?? 'Authentik';
}

public function getHexColor(): string
{
return '#fd4b2d';
}

public static function register(): self
{
return new self();
}
}
36 changes: 36 additions & 0 deletions app/Extensions/OAuth/Providers/CommonProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

namespace App\Extensions\OAuth\Providers;

final class CommonProvider extends OAuthProvider
{
protected function __construct(private string $id, private ?string $providerClass, private ?string $icon, private ?string $hexColor)
{
parent::__construct();
}

public function getId(): string
{
return $this->id;
}

public function getProviderClass(): ?string
{
return $this->providerClass;
}

public function getIcon(): ?string
{
return $this->icon;
}

public function getHexColor(): ?string
{
return $this->hexColor;
}

public static function register(string $id, ?string $providerClass = null, ?string $icon = null, ?string $hexColor = null): static
{
return new self($id, $providerClass, $icon, $hexColor);
}
}
57 changes: 57 additions & 0 deletions app/Extensions/OAuth/Providers/DiscordProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php

namespace App\Extensions\OAuth\Providers;

use Filament\Forms\Components\Placeholder;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Wizard\Step;
use Illuminate\Support\HtmlString;
use Illuminate\Support\Str;
use SocialiteProviders\Discord\Provider;
use Webbingbrasil\FilamentCopyActions\Forms\Actions\CopyAction;

final class DiscordProvider extends OAuthProvider
{
public function getId(): string
{
return 'discord';
}

public function getProvider(): string
{
return Provider::class;
}

public function getSetupSteps(): array
{
return array_merge([
Step::make('Register new Discord OAuth App')
->schema([
Placeholder::make('')
->content(new HtmlString('<p>Visit the <u><a href="https://discord.com/developers/applications" target="_blank">Discord Developer Portal</a></u> and click on <b>New Application</b>. Enter a <b>Name</b> (e.g. your panel name) and click on <b>Create</b>.</p><p>Copy the <b>Client ID</b> and the <b>Client Secret</b>, you will need them in the final step.</p>')),
Placeholder::make('')
->content(new HtmlString('<p>Under <b>Redirects</b> add the below URL.</p>')),
TextInput::make('_noenv_redirect')
->label('Redirect URL')
->disabled()
->hintAction(CopyAction::make())
->formatStateUsing(fn () => config('app.url') . (Str::endsWith(config('app.url'), '/') ? '' : '/') . 'auth/oauth/callback/discord'),
]),
], parent::getSetupSteps());
}

public function getIcon(): string
{
return 'tabler-brand-discord-f';
}

public function getHexColor(): string
{
return '#5865F2';
}

public static function register(): self
{
return new self();
}
}
56 changes: 56 additions & 0 deletions app/Extensions/OAuth/Providers/GithubProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php

namespace App\Extensions\OAuth\Providers;

use Filament\Forms\Components\Placeholder;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Wizard\Step;
use Illuminate\Support\HtmlString;
use Illuminate\Support\Str;
use Webbingbrasil\FilamentCopyActions\Forms\Actions\CopyAction;

final class GithubProvider extends OAuthProvider
{
public function getId(): string
{
return 'github';
}

public function getSetupSteps(): array
{
return array_merge([
Step::make('Register new Github OAuth App')
->schema([
Placeholder::make('')
->content(new HtmlString('<p>Visit the <u><a href="https://github.com/settings/developers" target="_blank">Github Developer Dashboard</a></u>, go to <b>OAuth Apps</b> and click on <b>New OAuth App</b>.</p><p>Enter an <b>Application name</b> (e.g. your panel name), set <b>Homepage URL</b> to your panel url and enter the below url as <b>Authorization callback URL</b>.</p>')),
TextInput::make('_noenv_callback')
->label('Authorization callback URL')
->disabled()
->hintAction(CopyAction::make())
->default(fn () => config('app.url') . (Str::endsWith(config('app.url'), '/') ? '' : '/') . 'auth/oauth/callback/github'),
Placeholder::make('')
->content(new HtmlString('<p>When you filled all fields click on <b>Register application</b>.</p>')),
]),
Step::make('Create Client Secret')
->schema([
Placeholder::make('')
->content(new HtmlString('<p>Once you registered your app, generate a new <b>Client Secret</b>.</p><p>You will also need the <b>Client ID</b>.</p>')),
]),
], parent::getSetupSteps());
}

public function getIcon(): string
{
return 'tabler-brand-github-f';
}

public function getHexColor(): string
{
return '#4078c0';
}

public static function register(): self
{
return new self();
}
}
112 changes: 112 additions & 0 deletions app/Extensions/OAuth/Providers/OAuthProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
<?php

namespace App\Extensions\OAuth\Providers;

use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Wizard\Step;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Str;
use SocialiteProviders\Manager\SocialiteWasCalled;

abstract class OAuthProvider
{
protected static array $providers = [];

public static function get(?string $id = null): array|self
{
return $id ? static::$providers[$id] : static::$providers;
}

protected function __construct()
{
if (array_key_exists($this->getId(), static::$providers)) {
logger()->warning("Tried to create duplicate OAuth provider with id '{$this->getId()}'");

return;
}

config()->set('services.' . $this->getId(), array_merge($this->getServiceConfig(), ['redirect' => '/auth/oauth/callback/' . $this->getId()]));

if ($this->getProviderClass()) {
Event::listen(function (SocialiteWasCalled $event) {
$event->extendSocialite($this->getId(), $this->getProviderClass());
});
}

static::$providers[$this->getId()] = $this;
}

abstract public function getId(): string;

public function getProviderClass(): ?string
{
return null;
}

public function getServiceConfig(): array
{
$id = Str::upper($this->getId());

return [
'client_id' => env("OAUTH_{$id}_CLIENT_ID"),
'client_secret' => env("OAUTH_{$id}_CLIENT_SECRET"),
];
}

public function getSettingsForm(): array
{
$id = Str::upper($this->getId());

return [
TextInput::make("OAUTH_{$id}_CLIENT_ID")
->label('Client ID')
->placeholder('Client ID')
->columnSpan(2)
->required()
->password()
->revealable()
->autocomplete(false)
->default(env("OAUTH_{$id}_CLIENT_ID")),
TextInput::make("OAUTH_{$id}_CLIENT_SECRET")
->label('Client Secret')
->placeholder('Client Secret')
->columnSpan(2)
->required()
->password()
->revealable()
->autocomplete(false)
->default(env("OAUTH_{$id}_CLIENT_SECRET")),
];
}

public function getSetupSteps(): array
{
return [
Step::make('OAuth Config')
->columns(4)
->schema($this->getSettingsForm()),
];
}

public function getName(): string
{
return Str::title($this->getId());
}

public function getIcon(): ?string
{
return null;
}

public function getHexColor(): ?string
{
return null;
}

public function isEnabled(): bool
{
$id = Str::upper($this->getId());

return env("OAUTH_{$id}_ENABLED", false);
}
}
Loading
Loading