commit d4fc0f73a2c55909243b480e7a1a9d64304cfecf Author: Martin Bean Date: Fri May 22 13:32:55 2020 +0100 Initial commit diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..677e36e --- /dev/null +++ b/.editorconfig @@ -0,0 +1,9 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_size = 4 +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = true diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8b7ef35 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/vendor +composer.lock diff --git a/README.md b/README.md new file mode 100644 index 0000000..a6b27ed --- /dev/null +++ b/README.md @@ -0,0 +1,89 @@ +# Discord provider for Laravel Socialite +A provider for [Laravel Socialite][1] that allows authentication as a Discord user. +_Authenticating as a bot is currently not supported._ + +## Installation +``` +composer require martinbean/socialite-discord-provider +``` + +## Usage +The package registers a Socialite driver with the name of `discord`. + +Before using the driver, create an OAuth application in Discord’s developer portal: +https://discord.com/developers/applications + +Set your client ID and client secret as environment variables, and then reference them in your **config/services.php** file. +You will also need to add a redirect URL to your application. + +```php + [ + 'client_id' => env('DISCORD_CLIENT_ID'), + 'client_secret' => env('DISCORD_CLIENT_SECRET'), + 'redirect' => '/auth/discord/callback', + ], + +]; +``` + +The `redirect` value will need to match a redirect URL in your Discord application settings. It can be relative as above. + +Then, create a controller to redirect and handle the token callback: + +```php +redirect(); + } + + /** + * Obtain the user information from Discord. + * + * @return \Illuminate\Http\Response + */ + public function handleProviderCallback() + { + $user = Socialite::driver('discord')->user(); + + // $user->token; + } +} +``` + +### Scopes +Discord supports various scopes. You can find a list here: https://discord.com/developers/docs/topics/oauth2#shared-resources-oauth2-scopes +To request additional scopes when authenticating, you can use the `scopes` method before redirecting: + +```php +return Socialite::driver('discord') + ->scopes(['guilds', 'messages.read']) + ->redirect(); +``` + +## Issues +If you have any problems using this package, please open an issue on the [GitHub repository][2]. + +[1] https://laravel.com/docs/master/socialite +[2]: https://github.com/martinbean/socialite-discord-provider diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..55a9173 --- /dev/null +++ b/composer.json @@ -0,0 +1,43 @@ +{ + "name": "martinbean/socialite-discord-provider", + "description": "A Discord provider for Laravel Socialite.", + "version": "1.0", + "type": "library", + "keywords": [ + "laravel", + "socialite", + "discord", + "oauth" + ], + "readme": "README.md", + "license": "MIT", + "authors": [ + { + "name": "Martin Bean", + "email": "martin@martinbean.co.uk", + "homepage": "https://martinbean.co.uk" + } + ], + "support": { + "issues": "https://github.com/martinbean/socialite-discord-provider/issues", + "source": "https://github.com/martinbean/socialite-discord-provider" + }, + "require": { + "laravel/socialite": "^4.0" + }, + "autoload": { + "psr-4": { + "MartinBean\\Laravel\\Socialite\\": "src/" + } + }, + "config": { + "sort-packages": true + }, + "extra": { + "laravel": { + "providers": [ + "MartinBean\\Laravel\\Socialite\\DiscordServiceProvider" + ] + } + } +} diff --git a/src/DiscordProvider.php b/src/DiscordProvider.php new file mode 100644 index 0000000..358094d --- /dev/null +++ b/src/DiscordProvider.php @@ -0,0 +1,82 @@ +buildAuthUrlFromBase('https://discord.com/api/oauth2/authorize', $state); + } + + /** + * {@inheritDoc} + */ + protected function getTokenUrl() + { + return 'https://discord.com/api/oauth2/token'; + } + + /** + * {@inheritDoc} + */ + protected function getUserByToken($token) + { + $userUrl = 'https://discord.com/api/users/@me'; + + $response = $this->getHttpClient()->get($userUrl, [ + 'headers' => [ + 'Authorization' => 'Bearer '.$token, + ], + ]); + + return json_decode($response->getBody(), true); + } + + /** + * {@inheritDoc} + */ + protected function mapUserToObject(array $user) + { + return (new User())->setRaw($user)->map([ + 'id' => $user['id'], + 'name' => $user['username'], + 'email' => $user['email'], + 'avatar' => sprintf('https://cdn.discordapp.com/avatars/%s/%s.png', $user['id'], $user['avatar']), + ]); + } + + /** + * {@inheritDoc} + */ + protected function getTokenFields($code) + { + return [ + 'client_id' => $this->clientId, + 'client_secret' => $this->clientSecret, + 'code' => $code, + 'grant_type' => 'authorization_code', + 'redirect_uri' => $this->redirectUrl, + ]; + } +} diff --git a/src/DiscordServiceProvider.php b/src/DiscordServiceProvider.php new file mode 100644 index 0000000..6e8774f --- /dev/null +++ b/src/DiscordServiceProvider.php @@ -0,0 +1,34 @@ +make('config')->get('services.discord'); + + $redirect = value(Arr::get($config, 'redirect')); + + return new DiscordProvider( + $app->make('request'), + Arr::get($config, 'client_id', ''), + Arr::get($config, 'client_secret', ''), + Str::startsWith($redirect, '/') ? $app->make('url')->to($redirect) : $redirect, + Arr::get($config, 'guzzle', []) + ); + }); + } +}