For the complete documentation index, see llms.txt. This page is also available as Markdown.

Свой сервис входа

Модуль может добавить вход через ещё один сервис — Discord, Mail.ru, Telegram, что угодно — не трогая ядро. Маршруты, state, PKCE, связывание аккаунтов и создание сессии остаются в ядре; модуль отвечает только за свой сервис.

Типовой случай: OAuth 2.0

Наследник AbstractOAuth2Provider — это три адреса и маппинг полей:

namespace Vasya\Discord\Infrastructure\Auth;

use Johncms\Auth\External\AbstractOAuth2Provider;
use Johncms\Auth\External\ExternalIdentityDTO;

final class DiscordProvider extends AbstractOAuth2Provider
{
    public function key(): string
    {
        // Ключ уходит в URL, в конфиг и в таблицу user_identities. Не переименовывается.
        return 'discord';
    }

    public function label(): string
    {
        return 'Discord';
    }

    protected function authorizeUrl(): string
    {
        return 'https://discord.com/oauth2/authorize';
    }

    protected function tokenUrl(): string
    {
        return 'https://discord.com/api/oauth2/token';
    }

    protected function userInfoUrl(): string
    {
        return 'https://discord.com/api/users/@me';
    }

    protected function scope(): string
    {
        return 'identify email';
    }

    protected function mapIdentity(array $userInfo, array $token): ExternalIdentityDTO
    {
        return new ExternalIdentityDTO(
            providerUserId: (string) $userInfo['id'],
            email: $userInfo['email'] ?? null,
            emailVerified: (bool) ($userInfo['verified'] ?? false),
            nickname: $userInfo['username'] ?? null,
        );
    }
}

Регистрация — в config/services.php модуля:

Тег johncms.auth.external_provider ядро вешает само на всё, что реализует ExternalIdentityProviderInterface, — при условии, что сервис объявлен с autoconfigure() (так работает и $services->load(...) для целого каталога). Без autoconfigure тег указывают явно:

Маршруты модулю не нужны: /auth/discord и /auth/discord/callback — ядровые и параметризованы ключом. Ключи приложения администратор вводит в /admin/auth/providers, там же берёт адрес возврата.

Нетиповой случай

Если сервис не про authorization code flow — Telegram Login Widget (подписанный payload, никакого code), Steam (OpenID 2.0), — реализуйте ExternalIdentityProviderInterface напрямую. Контракт специально не привязан к OAuth2 и описывает две точки: «куда отправить пользователя» и «что делать, когда он вернулся».

Если сервису нужно что-то ещё из callback — VK ID, например, требует device_id оттуда в запросе токена — переопределите exchangeCode(): третьим аргументом туда приходит ExternalCallbackDTO.

Провайдер не получает Request: HTTP-типы не выходят за пределы HTTP-слоя, а провайдер — адаптер к чужому API. Контроллер ядра собирает ExternalCallbackDTO с параметрами запроса и передаёт его вместе с ExternalAuthContextDTO (адрес возврата, state, PKCE-verifier).

Про emailVerified

Флаг решает, будет ли аккаунт автоматически связан с существующим по адресу. Ставьте true, только если сервис действительно подтверждает адрес. Ошибка здесь — это захват чужого аккаунта: достаточно зарегистрироваться у провайдера с адресом жертвы.

Переводы

Подпись кнопки — обычная строка своего gettext-домена (d__('discord', '...')) или просто название сервиса, которое не переводится.

Что нельзя испортить

Провайдер не управляет флоу: он не видит запрос, не хранит state, не создаёт сессию и не решает, с каким аккаунтом связать личность. Максимум, что он может сломать, — свою же кнопку.

Последнее обновление

Это было полезно?