Integrações Social (OAuth) v4
A MuCRM não embute um provider OAuth completo no Core. O padrão recomendado na v2 é: OAuth no seu plugin → vincular identidade → emitir Bearer MuCRM (ou usar sessão web).
Arquitetura sugerida
Usuário clica "Entrar com Discord"
│
▼
Plugin SocialAuth -> redirect OAuth (Discord/Twitch)
│
▼
Callback (withoutCsrf) -> troca code por access_token do provedor
│
▼
Busca/cria vínculo (discord_id ↔ id)
│
▼
Sessão web OU create_login_token() / create_token('discord', [...])Callback sem CSRF
use MUCRM\engine\support\facades\uri;
use MUCRM\modules\social_auth\handlers\discord_handler;
uri::get('/oauth/discord/callback', [discord_handler::class, 'callback'])
->without_csrf()
->name('oauth.discord.callback');🚨Valide o state
Sempre use
state CSRF-like no fluxo OAuth e rejeite callbacks sem state válido — withoutCsrf só remove o token de formulário MuCRM.Após o OAuth: emitir token MuCRM
$customer = customer::where('id', $account_id)->first_or_fail();
auth::login($customer, 'user');
$token = $customer->create_token('discord', ['profile:read'])->plainTextToken;
return json(['success' => true, 'token' => $token]);HTTP Client do Core
Use o cliente embutido para falar com as APIs Discord/Twitch:
use MUCRM\engine\http\http;
use MUCRM\engine\support\log;
$response = http::as_form()->post('https://discord.com/api/oauth2/token', [
'client_id' => config('social.discord.client_id'),
'client_secret' => config('social.discord.client_secret'),
'grant_type' => 'authorization_code',
'code' => $code,
'redirect_uri' => config('social.discord.redirect'),
]);
if ($response->failed()) {
log::channel('api')->error('OAuth Discord falhou', ['body' => $response->body()]);
return json(['error' => 'oauth_failed'], 502);
}
$oauth = $response->json();Detalhes do client: Cliente HTTP.
Checklist
- Credenciais em
bootstrap/config/(nunca no repositório público) - Callback com
withoutCsrf+ validação destate - Vínculo estável no banco (
discord_id,twitch_id) - Abilities mínimas no token emitido
- IP/domínio do callback em
auth.allowedse a API estiver fechada