diff --git a/composer.json b/composer.json index 70449dbeb..5146e035b 100644 --- a/composer.json +++ b/composer.json @@ -51,7 +51,6 @@ "azure-oss/storage-blob-flysystem": "^1.2", "brianium/paratest": "^7.14", "carthage-software/mago": "1.0.0-beta.28", - "depotwarehouse/oauth2-twitch": "^1.3", "guzzlehttp/psr7": "^2.6.1", "league/flysystem-aws-s3-v3": "^3.25.1", "league/flysystem-ftp": "^3.25.1", @@ -88,6 +87,7 @@ "tempest/blade": "dev-main", "thenetworg/oauth2-azure": "^2.2", "twig/twig": "^3.16", + "vertisan/oauth2-twitch-helix": "^2.0", "wohali/oauth2-discord-new": "^1.2" }, "replace": { diff --git a/docs/2-features/17-oauth.md b/docs/2-features/17-oauth.md index 75ac6dc59..902869ce9 100644 --- a/docs/2-features/17-oauth.md +++ b/docs/2-features/17-oauth.md @@ -220,6 +220,7 @@ Tempest provides a different configuration object for each OAuth provider. Below - **Microsoft** authentication using {b`Tempest\Auth\OAuth\Config\MicrosoftOAuthConfig`}, - **Slack** authentication using {b`Tempest\Auth\OAuth\Config\SlackOAuthConfig`}, - **Apple** authentication using {b`Tempest\Auth\OAuth\Config\AppleOAuthConfig`}, +- **Twitch** authentication using {b`Tempest\Auth\OAuth\Config\TwitchOAuthConfig`}, - Any other OAuth platform using {b`Tempest\Auth\OAuth\Config\GenericOAuthConfig`}. ## Testing diff --git a/packages/auth/composer.json b/packages/auth/composer.json index 687412af4..4a83377c2 100644 --- a/packages/auth/composer.json +++ b/packages/auth/composer.json @@ -22,7 +22,7 @@ "adam-paterson/oauth2-slack": "^1.1", "wohali/oauth2-discord-new": "^1.2", "smolblog/oauth2-twitter": "^1.0", - "depotwarehouse/oauth2-twitch": "^1.3" + "vertisan/oauth2-twitch-helix": "^2.0" }, "autoload": { "psr-4": { diff --git a/packages/auth/src/Installer/OAuthInstaller.php b/packages/auth/src/Installer/OAuthInstaller.php index 0ee15ec40..8915b44d3 100644 --- a/packages/auth/src/Installer/OAuthInstaller.php +++ b/packages/auth/src/Installer/OAuthInstaller.php @@ -93,8 +93,7 @@ private function publishConfig(SupportedOAuthProvider $provider): void private function publishController(SupportedOAuthProvider $provider): void { - $fileName = str($provider->value) - ->classBasename() + $fileName = str($provider->getName()) ->replace('Provider', '') ->append('Controller.php') ->toString(); @@ -104,7 +103,7 @@ private function publishController(SupportedOAuthProvider $provider): void destination: src_path("Authentication/OAuth/{$fileName}"), callback: function (string $source, string $destination) use ($provider) { $providerFqcn = $provider::class; - $name = strtolower($provider->name); + $name = strtolower($provider->getName()); $userModelFqcn = to_fqcn(src_path('Authentication/User.php'), root: root_path()); $this->update( diff --git a/packages/auth/src/Installer/oauth/twitch.config.stub.php b/packages/auth/src/Installer/oauth/twitch.config.stub.php new file mode 100644 index 000000000..11968506f --- /dev/null +++ b/packages/auth/src/Installer/oauth/twitch.config.stub.php @@ -0,0 +1,15 @@ + $this->clientId, + 'clientSecret' => $this->clientSecret, + 'redirectUri' => $this->redirectTo, + ]); + } + + /** + * @param TwitchHelixResourceOwner $resourceOwner + */ + public function mapUser(ObjectFactory $factory, ResourceOwnerInterface $resourceOwner): OAuthUser + { + return $factory->withData([ + 'id' => (string) $resourceOwner->getId(), + 'email' => $resourceOwner->getEmail(), + 'name' => $resourceOwner->getDisplayName(), + 'nickname' => $resourceOwner->getDisplayName(), + 'avatar' => $resourceOwner->getProfileImageUrl(), + 'provider' => $this->provider, + 'raw' => $resourceOwner->toArray(), + ])->to(OAuthUser::class); + } +} diff --git a/packages/auth/src/OAuth/SupportedOAuthProvider.php b/packages/auth/src/OAuth/SupportedOAuthProvider.php index 1346a942d..023a2ecc0 100644 --- a/packages/auth/src/OAuth/SupportedOAuthProvider.php +++ b/packages/auth/src/OAuth/SupportedOAuthProvider.php @@ -11,6 +11,7 @@ use League\OAuth2\Client\Provider\Instagram; use League\OAuth2\Client\Provider\LinkedIn; use Stevenmaguire\OAuth2\Client\Provider\Microsoft; +use Vertisan\OAuth2\Client\Provider\TwitchHelix; use Wohali\OAuth2\Client\Provider\Discord; enum SupportedOAuthProvider: string @@ -25,7 +26,35 @@ enum SupportedOAuthProvider: string case LINKEDIN = LinkedIn::class; case MICROSOFT = Microsoft::class; case SLACK = Slack::class; + case TWITCH = TwitchHelix::class; + /** + * Returns the canonical name for the given OAuth provider. Required because some of the providers have mixed-case names. + * + * @return string|null The canonical name, or null if the provider is generic. + */ + public function getName(): ?string + { + return match ($this) { + self::APPLE => 'Apple', + self::DISCORD => 'Discord', + self::FACEBOOK => 'Facebook', + self::GENERIC => null, + self::GITHUB => 'Github', + self::GOOGLE => 'Google', + self::INSTAGRAM => 'Instagram', + self::LINKEDIN => 'LinkedIn', + self::MICROSOFT => 'Microsoft', + self::SLACK => 'Slack', + self::TWITCH => 'Twitch', + }; + } + + /** + * Returns the Composer package name for the given OAuth provider. + * + * @return string|null The Composer package name, or null if the provider is generic. + */ public function composerPackage(): ?string { return match ($this) { @@ -39,6 +68,7 @@ public function composerPackage(): ?string self::LINKEDIN => 'league/oauth2-linkedin', self::MICROSOFT => 'stevenmaguire/oauth2-microsoft', self::SLACK => 'adam-paterson/oauth2-slack', + self::TWITCH => 'vertisan/oauth2-twitch-helix', }; } } diff --git a/tests/Integration/Auth/Installer/OAuthInstallerTest.php b/tests/Integration/Auth/Installer/OAuthInstallerTest.php index 22e754b60..40a7eb5f1 100644 --- a/tests/Integration/Auth/Installer/OAuthInstallerTest.php +++ b/tests/Integration/Auth/Installer/OAuthInstallerTest.php @@ -121,6 +121,11 @@ public static function oauthProvider(): array 'expectedConfigPath' => 'App/Authentication/OAuth/slack.config.php', 'expectedControllerPath' => 'App/Authentication/OAuth/SlackController.php', ], + 'twitch' => [ + 'provider' => SupportedOAuthProvider::TWITCH, + 'expectedConfigPath' => 'App/Authentication/OAuth/twitch.config.php', + 'expectedControllerPath' => 'App/Authentication/OAuth/TwitchController.php', + ], ]; } }