Add bot support

This commit is contained in:
Martin Bean 2020-07-09 18:52:23 +01:00
parent 5c10e0f1e8
commit 7a28af23dd
6 changed files with 238 additions and 11 deletions

View File

@ -1,10 +1,9 @@
# 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._
A provider for [Laravel Socialite][1] that allows authentication as a Discord user or bot.
## Installation
```
composer require martinbean/socialite-discord-provider
composer require martinbean/socialite-discord-provider:^1.1
```
## Usage
@ -13,8 +12,7 @@ The package registers a Socialite driver with the name of `discord`.
Before using the driver, create an OAuth application in Discords 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.
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 if you intend to authenticate as a user.
```php
<?php
@ -36,7 +34,8 @@ return [
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:
### Authenticating as a user
Create a controller to redirect and handle the access token callback:
```php
<?php
@ -72,8 +71,9 @@ class DiscordController extends Controller
}
```
### Scopes
Discord supports various scopes. You can find a list here: https://discord.com/developers/docs/topics/oauth2#shared-resources-oauth2-scopes
#### Scopes
Discord supports various scopes when authenticating as a user. 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
@ -82,6 +82,54 @@ return Socialite::driver('discord')
->redirect();
```
### Authenticating as a bot
Discord allows you to add “bots” to guilds (servers). This is a modified OAuth flow, where you are redirected to Discord to confirm the guild you wish to add a bot to. There is no redirect back to your application when you authorize the request.
You can authenticate as a bot by using the `bot` method before redirecting:
```php
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Laravel\Socialite\Facades\Socialite;
class DiscordController extends Controller
{
/**
* Redirect the user to the Discord authentication page.
*
* @return \Illuminate\Http\Response
*/
public function redirectToProvider()
{
return Socialite::driver('discord')->bot()->redirect();
}
}
```
If you know the guild ID you wish to add your bot to, you may specify it with the `guild` method:
```php
return Socialite::driver('discord')
->bot()
->guild($guildId)
->redirect();
```
Additionally, you can disable the guild select:
```php
return Socialite::driver('discord')
->bot()
->guild($guildId)
->disableGuildSelect()
->redirect();
```
**Note:** if you try and disable guild selection without specifying a guild, the package will throw a `GuildRequiredException` instance.
## Issues
If you have any problems using this package, please open an issue on the [GitHub repository][2].

View File

@ -1,7 +1,7 @@
{
"name": "martinbean/socialite-discord-provider",
"description": "A Discord provider for Laravel Socialite.",
"version": "1.0",
"version": "1.1.0",
"type": "library",
"keywords": [
"laravel",
@ -23,6 +23,7 @@
"source": "https://github.com/martinbean/socialite-discord-provider"
},
"require": {
"facade/ignition-contracts": "^1.0",
"laravel/socialite": "^4.0"
},
"autoload": {

139
src/BotRedirectBuilder.php Normal file
View File

@ -0,0 +1,139 @@
<?php
namespace MartinBean\Laravel\Socialite;
use Illuminate\Http\RedirectResponse;
use MartinBean\Laravel\Socialite\Exceptions\GuildRequiredException;
class BotRedirectBuilder
{
/**
* The client ID.
*
* @var string
*/
protected $clientId;
/**
* The permissions to request.
*
* @var int
*/
protected $permissions = 0;
/**
* The guild to pre-fill the dropdown picker with.
*
* @var string
*/
protected $guild;
/**
* Whether to disallow the user from changing the guild dropdown.
*
* @var bool
*/
protected $disableGuildSelect = false;
/**
* Create a new bot redirect builder instance.
*
* @param string $clientId
* @return void
*/
public function __construct(string $clientId)
{
$this->clientId = $clientId;
}
/**
* Set the permissions to request.
*
* @param int $permissions
* @return $this
*/
public function permissions(int $permissions)
{
$this->permissions = $permissions;
return $this;
}
/**
* Pre-fill the dropdown picker with a guild for the user.
*
* @param string|int $guild
* @return $this
*/
public function guild($guild)
{
$this->guild = (string) $guild;
return $this;
}
/**
* Disallow the user from changing the guild dropdown.
*
* @return $this
*/
public function disableGuildSelect()
{
$this->disableGuildSelect = true;
return $this;
}
/**
* Redirect the user of the application to the provider's authentication screen.
*
* @return \Illuminate\Http\RedirectResponse
*/
public function redirect()
{
return new RedirectResponse($this->getAuthUrl());
}
/**
* Get the authentication URL for the provider.
*
* @param string $url
* @return string
*/
protected function buildAuthUrlFromBase($url)
{
return $url.'?'.http_build_query($this->getCodeFields(), '', '&', PHP_QUERY_RFC1738);
}
/**
* Get the GET parameters for the code request.
*
* @return array
*
* @throws \MartinBean\Laravel\Socialite\Exceptions\GuildRequiredException
*/
protected function getCodeFields()
{
if ($this->disableGuildSelect && ! $this->guild) {
throw new GuildRequiredException();
}
return [
'client_id' => $this->clientId,
'scope' => 'bot',
'permissions' => $this->permissions,
'guild_id' => $this->guild,
'disable_guild_select' => $this->disableGuildSelect ? 'true' : 'false',
];
}
/**
* Get the authentication URL for the provider.
*
* @return string
*/
protected function getAuthUrl()
{
return $this->buildAuthUrlFromBase('https://discord.com/api/oauth2/authorize');
}
}

View File

@ -21,6 +21,16 @@ class DiscordProvider extends AbstractProvider implements ProviderInterface
*/
protected $scopeSeparator = ' ';
/**
* Create a new bot redirect.
*
* @return \MartinBean\Laravel\Socialite\BotRedirectBuilder
*/
public function bot()
{
return new BotRedirectBuilder($this->clientId);
}
/**
* {@inheritDoc}
*/

View File

@ -24,8 +24,8 @@ class DiscordServiceProvider extends ServiceProvider
return new DiscordProvider(
$app->make('request'),
Arr::get($config, 'client_id', ''),
Arr::get($config, 'client_secret', ''),
$config['client_id'],
$config['client_secret'],
Str::startsWith($redirect, '/') ? $app->make('url')->to($redirect) : $redirect,
Arr::get($config, 'guzzle', [])
);

View File

@ -0,0 +1,29 @@
<?php
namespace MartinBean\Laravel\Socialite\Exceptions;
use Facade\IgnitionContracts\BaseSolution;
use Facade\IgnitionContracts\ProvidesSolution;
use Facade\IgnitionContracts\Solution;
use RuntimeException;
class GuildRequiredException extends RuntimeException implements ProvidesSolution
{
/**
* The exception message.
*
* @var string
*/
protected $message = 'A guild is required if you are going to disable the guild select';
/**
* Get the exception solution.
*
* @return \Facade\IgnitionContracts\Solution
*/
public function getSolution(): Solution
{
return BaseSolution::create('Specify a guild ID before redirecting')
->setSolutionDescription('Call `guild($guildId)` before redirecting.');
}
}