PHPackages                             padosoft/laravel-rebel-channel-discord - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Authentication &amp; Authorization](/categories/authentication)
4. /
5. padosoft/laravel-rebel-channel-discord

ActiveLibrary[Authentication &amp; Authorization](/categories/authentication)

padosoft/laravel-rebel-channel-discord
======================================

Discord delivery channel for Laravel Rebel Channels: ship security/SOC alerts (anomaly cases, lockouts, high-risk events) and notifications to a Discord channel via webhook. Part of padosoft/laravel-rebel-\*.

v0.1.1(1mo ago)07MITPHPPHP ^8.3CI passing

Since Jun 4Pushed 1mo agoCompare

[ Source](https://github.com/padosoft/laravel-rebel-channel-discord)[ Packagist](https://packagist.org/packages/padosoft/laravel-rebel-channel-discord)[ Docs](https://github.com/padosoft/laravel-rebel-channel-discord)[ RSS](/packages/padosoft-laravel-rebel-channel-discord/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (2)Dependencies (20)Versions (4)Used By (0)

Laravel Rebel — Discord Channel
===============================

[](#laravel-rebel--discord-channel)

> Official documentation:

> **Ship your security alerts to Discord, the Rebel way.** This package plugs a Discord [incoming webhook](https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks)into [`laravel-rebel-channels`](https://github.com/padosoft/laravel-rebel-channels) as a `MessageDeliveryChannel` — so your **SOC/security alerts** (anomaly cases, account lockouts, high-risk logins) and notifications land in a Discord channel, with Rebel's HMAC'd audit trail on top. Part of the `padosoft/laravel-rebel-*` suite.

 [![Laravel Rebel](resources/screenshoots/Laravel-Rebel-banner.png)](resources/screenshoots/Laravel-Rebel-banner.png)

 [![Laravel 12|13](https://camo.githubusercontent.com/9e9b743bcbf97a29fe735334a4a8e906d05d60310969905af6607cef8da30138/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c61726176656c2d313225323025374325323031332d4646324432303f7374796c653d666c61742d737175617265266c6f676f3d6c61726176656c266c6f676f436f6c6f723d7768697465)](https://camo.githubusercontent.com/9e9b743bcbf97a29fe735334a4a8e906d05d60310969905af6607cef8da30138/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c61726176656c2d313225323025374325323031332d4646324432303f7374796c653d666c61742d737175617265266c6f676f3d6c61726176656c266c6f676f436f6c6f723d7768697465) [![PHP 8.3+](https://camo.githubusercontent.com/6aa777dd33ef43fbef727d8187b578003a61e5dc41bbc958b0938c996cdc92f2/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d382e33253230253743253230382e34253230253743253230382e352d3737374242343f7374796c653d666c61742d737175617265266c6f676f3d706870266c6f676f436f6c6f723d7768697465)](https://camo.githubusercontent.com/6aa777dd33ef43fbef727d8187b578003a61e5dc41bbc958b0938c996cdc92f2/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d382e33253230253743253230382e34253230253743253230382e352d3737374242343f7374796c653d666c61742d737175617265266c6f676f3d706870266c6f676f436f6c6f723d7768697465) [![PHPStan max](https://camo.githubusercontent.com/4b9a3c97d76534abb905e64bd9e5bb9f13fe68e962071e0ccbbe7b629112f11c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048505374616e2d6d61782d3241364644423f7374796c653d666c61742d737175617265)](https://camo.githubusercontent.com/4b9a3c97d76534abb905e64bd9e5bb9f13fe68e962071e0ccbbe7b629112f11c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048505374616e2d6d61782d3241364644423f7374796c653d666c61742d737175617265) [![Pest 4](https://camo.githubusercontent.com/9b9da1d7d243a7465ab338e9374e47300a7fe2e26b5c291e7e3c95b53153789a/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f74657374732d50657374253230342d3232433535453f7374796c653d666c61742d737175617265)](https://camo.githubusercontent.com/9b9da1d7d243a7465ab338e9374e47300a7fe2e26b5c291e7e3c95b53153789a/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f74657374732d50657374253230342d3232433535453f7374796c653d666c61742d737175617265) [![Discord Webhook](https://camo.githubusercontent.com/b001d32c6f6d1b63581adebef30f88ffd33d688e85199dbe651ccf70dbce09db/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f446973636f72642d576562686f6f6b2d3538363546323f7374796c653d666c61742d737175617265266c6f676f3d646973636f7264266c6f676f436f6c6f723d7768697465)](https://camo.githubusercontent.com/b001d32c6f6d1b63581adebef30f88ffd33d688e85199dbe651ccf70dbce09db/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f446973636f72642d576562686f6f6b2d3538363546323f7374796c653d666c61742d737175617265266c6f676f3d646973636f7264266c6f676f436f6c6f723d7768697465) [![MIT](https://camo.githubusercontent.com/ac049ef4e7a0b7196b09add6ac2d4f180e544c0ac779c2b2ac2fd2723a209579/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d626c75653f7374796c653d666c61742d737175617265)](https://camo.githubusercontent.com/ac049ef4e7a0b7196b09add6ac2d4f180e544c0ac779c2b2ac2fd2723a209579/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d626c75653f7374796c653d666c61742d737175617265)

---

Table of contents
-----------------

[](#table-of-contents)

- [What it is](#what-it-is)
- [Quick glossary](#quick-glossary)
- [Why this package](#why-this-package)
- [Rebel + Discord vs the alternatives](#rebel--discord-vs-the-alternatives)
- [How it works (step by step)](#how-it-works-step-by-step)
- [Create a Discord webhook (step by step)](#create-a-discord-webhook-step-by-step)
- [Installation](#installation)
- [Configuration](#configuration)
- [Usage](#usage)
- [Telemetry &amp; the audit trail](#telemetry--the-audit-trail)
- [Live tests against the real webhook](#live-tests-against-the-real-webhook)
- [`.env.example`](#envexample)
- [Security notes](#security-notes)
- [🔋 Vibe coding with batteries included](#-vibe-coding-with-batteries-included)
- [Testing &amp; License](#testing--license)

---

What it is
----------

[](#what-it-is)

A thin, well-tested **Discord delivery channel** for Rebel Channels. It implements the Channels `MessageDeliveryChannel` contract (`key='discord'`, `supports(Channel::Discord)`) and posts a message to a Discord channel through an **incoming webhook** — no bot, no OAuth, just a URL.

Its first job is **delivering security/SOC alerts**: when Rebel detects an anomaly case, an account lockout, or a high-risk event, you forward a human-readable line to your `#soc-alerts` channel so the team sees it in real time. It also works for plain notifications or OTP delivery where Discord is an acceptable transport.

A small **gateway seam** (`DiscordGateway`) wraps the HTTP call, so the whole thing is unit-testable offline and has a real **live** test-suite for an actual webhook.

Depends on [`padosoft/laravel-rebel-core`](https://github.com/padosoft/laravel-rebel-core)and [`padosoft/laravel-rebel-channels`](https://github.com/padosoft/laravel-rebel-channels).

---

Quick glossary
--------------

[](#quick-glossary)

TermIn plain words**Incoming webhook**A per-channel URL Discord gives you. POST JSON to it and a message appears in that channel. No bot or login needed.**Webhook URL**`https://discord.com/api/webhooks//` — a **secret**: anyone with it can post to your channel.**SOC alert**A "Security Operations Center" notification — e.g. *"account #42 locked after 5 failed logins"*.**Delivery channel**A Rebel object that knows how to *send a message* over one transport (Discord, SMS, …). Here: Discord.**Audit event**A row Rebel writes to `rebel_auth_events` so the admin panel can show what happened (who, when, which channel).**Keyed HMAC**A one-way, peppered hash. We store the recipient as an HMAC, never in clear, so the audit trail leaks no PII.---

Why this package
----------------

[](#why-this-package)

★WhatIn short★★★**SOC alerts in Discord**Forward anomaly cases / lockouts / high-risk events to a channel your team already watches.★★★**Zero-bot setup**Just an incoming-webhook URL — no Discord bot, no OAuth, no gateway connection to maintain.★★★**Full Rebel telemetry**Every send writes a `channel.delivery.sent` / `.failed` audit event, so the panel's Channel Performance shows Discord traffic.★★**Never throws out**Any transport/HTTP error becomes a clean `provider_error` `DeliveryResult` — your alerting path never explodes.★★**Offline-testable**A gateway seam + fake means your tests don't hit Discord; a separate live suite does.★★**Safe by default**No webhook URL → nothing registers; the URL is treated as a secret and never logged.★**Privacy-first audit**The recipient (channel id) is stored only as a keyed HMAC.---

Rebel + Discord vs the alternatives
-----------------------------------

[](#rebel--discord-vs-the-alternatives)

Getting a security alert into Discord, four ways:

Capability**Rebel + this package**ShopifyDiscord bot (discord.php / Gateway)Raw `Http::post()` to a webhookSelf-hosted Discord **SOC-alert** channel✅❌➖ (you build it)➖ (you build it)No bot / no OAuth (just a webhook URL)✅❌❌✅Auto-wired into Rebel's delivery layer✅❌❌❌Graceful failure → clean `provider_error`✅❌❌❌ (you handle exceptions)Unified **audit trail** (recipient HMAC'd)✅❌❌❌Panel **Channel Performance** for Discord✅❌❌❌Webhook URL kept secret / never logged✅➖➖❌ (easy to leak in logs)Offline test seam + live suite✅❌➖❌> Legend: ✅ built-in · ➖ partial / DIY · ❌ not available. **Shopify** is a closed, hosted commerce platform: it has **no self-hosted Discord SOC-alert channel** at all — you can't point its auth/security events at your own Discord, self-host the sender, or get a unified, HMAC'd audit trail of deliveries. A black box, not a developer-facing security-alerting channel. A **Discord bot** can post too, but it means running a Gateway connection and OAuth you don't need for one-way alerts. A **raw `Http::post()`** works until you want graceful failure, a secret-safe URL, audit telemetry and tests — which is exactly what this package gives you for free.

---

How it works (step by step)
---------------------------

[](#how-it-works-step-by-step)

```
 Rebel detects something                 this package                         Discord
 (anomaly / lockout / high-risk)
        │
        │  $channel->send($recipient, "🚨 account #42 locked", Channel::Discord, $ctx)
        ▼
 ┌──────────────────────────┐   HMAC(recipient)   ┌───────────────────────┐
 │ DiscordDeliveryChannel   │────────────────────▶│  AuditLogger (core)   │  channel.delivery.sent
 │  • supports(Discord)     │                     │  → rebel_auth_events  │  / channel.delivery.failed
 │  • catches \Throwable    │                     └───────────────────────┘
 └───────────┬──────────────┘
             │ DiscordGateway::send($webhookUrl, {content})
             ▼
 ┌──────────────────────────┐   POST {"content": …}   ┌───────────────────┐
 │ HttpDiscordGateway       │────────────────────────▶│  Discord webhook  │ ──▶ message appears
 │ (Illuminate Http client) │     204 No Content      │  #soc-alerts      │     in your channel
 └──────────────────────────┘                         └───────────────────┘

```

1. Something in Rebel wants to alert you. It calls the Discord delivery channel's `send()`.
2. The channel HMACs the recipient (the Discord channel id) and asks the gateway to POST the message.
3. The gateway POSTs `{"content": ""}` (plus optional username/avatar) to your webhook URL. Discord replies `204 No Content` on success.
4. The channel records a `channel.delivery.sent` audit event (or `channel.delivery.failed` if the POST threw) — so the admin panel's Channel Performance shows the delivery. It returns a `DeliveryResult` either way; it **never throws out**.

---

Create a Discord webhook (step by step)
---------------------------------------

[](#create-a-discord-webhook-step-by-step)

1. In Discord, open the **server** and the **channel** you want alerts in (e.g. `#soc-alerts`). *(You need "Manage Webhooks" permission on that channel.)*
2. Click the **gear icon** (Edit Channel) next to the channel name.
3. Go to **Integrations → Webhooks → New Webhook**.
4. Give it a name (e.g. *"Rebel SOC"*) and optionally an avatar; make sure the target channel is selected.
5. Click **Copy Webhook URL**. It looks like `https://discord.com/api/webhooks/123456789012345678/AbCd…token`.
6. Put it in your `.env` as `DISCORD_WEBHOOK_URL` (see below). Done — the channel auto-registers.

> **Treat the URL as a secret.** Anyone who has it can post to your channel. Keep it out of version control (it's in `.gitignore` via `.env`) and never log it. To rotate it, delete the webhook in Discord and create a new one.

---

Installation
------------

[](#installation)

```
composer require padosoft/laravel-rebel-channel-discord
php artisan vendor:publish --tag="rebel-channel-discord-config"
```

Add your webhook URL to `.env`:

```
DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/123456789012345678/your-webhook-token
```

That's it — the delivery channel registers itself into the container under the key `discord` and is tagged `rebel.delivery-channels`.

---

Configuration
-------------

[](#configuration)

File `config/rebel-channel-discord.php`:

KeyDefaultWhat it does`webhook_url``env(DISCORD_WEBHOOK_URL)`The Discord incoming-webhook URL (a secret). The channel registers only when this is set.`username``env(DISCORD_WEBHOOK_USERNAME)`Optional per-message display-name override. `null` = use the webhook's default.`avatar_url``env(DISCORD_WEBHOOK_AVATAR_URL)`Optional per-message avatar override. `null` = use the webhook's default.`register_provider``true` (`env(REBEL_DISCORD_REGISTER)`)Auto-register the channel into the container (only when `webhook_url` is set). `false` = installed but dormant.---

Usage
-----

[](#usage)

The channel implements the Channels `MessageDeliveryChannel` contract. Resolve it (it's bound to the contract and tagged `rebel.delivery-channels`) and call `send()`:

```
use Padosoft\Rebel\Channels\Contracts\MessageDeliveryChannel;
use Padosoft\Rebel\Channels\Enums\Channel;
use Padosoft\Rebel\Core\Context\SecurityContext;
use Padosoft\Rebel\Core\Identifiers\PhoneIdentifier;

$discord = app(MessageDeliveryChannel::class); // the Discord channel (when it's the registered one)

// "recipient" identifies the Discord channel; its normalized value is HMAC'd for the audit trail.
$recipient = PhoneIdentifier::from('+10000000042'); // e.g. a numeric channel id you assign

$result = $discord->send(
    $recipient,
    '🚨 SOC: account #42 locked after 5 failed logins (IP risk: high)',
    Channel::Discord,
    SecurityContext::fromRequest($request),
);

if ($result->accepted()) {
    // delivered to Discord
} else {
    // $result->reason === 'provider_error' — log/alert via another path; we never threw
}
```

**Collect every delivery channel via the tag** (when you run several — Discord, Telegram, …):

```
use Padosoft\Rebel\Channel\Discord\RebelDiscordServiceProvider;
use Padosoft\Rebel\Channels\Enums\Channel;

/** @var iterable $channels */
$channels = app()->tagged(RebelDiscordServiceProvider::DELIVERY_TAG);

foreach ($channels as $channel) {
    if ($channel->supports(Channel::Discord)) {
        $channel->send($recipient, $message, Channel::Discord, $context);
    }
}
```

> **Recipient note.** This channel reuses the core `PhoneIdentifier` as the *recipient* value object (the suite's delivery contract is typed on it). Its `normalized()` value is treated as the **Discord channel/webhook id** and is only ever stored as a keyed HMAC. The actual POST target is always the configured `webhook_url` — so one configured channel maps to one Discord channel.

---

Telemetry &amp; the audit trail
-------------------------------

[](#telemetry--the-audit-trail)

Delivery is only useful if you can *see* it. On **every** send this channel records one Rebel audit event through the core `AuditLogger` (persisted to `rebel_auth_events`; sync or queued per your core config), so the admin panel's **Channel Performance** shows Discord traffic — successes and failures alike.

OutcomeAudit `event_type``channel``provider`Webhook accepted the post`channel.delivery.sent``discord``discord`Gateway threw (any error)`channel.delivery.failed``discord``discord`Each event stores the recipient as a **keyed HMAC** (`identifierHmac` + `keyVersion`, never in clear) and a `metadata` object:

```
{
  "message_status": "sent",
  "error_code": null
}
```

On failure, `message_status` is `"failed"` and `error_code` is `"provider_error"`. The webhook URL and the message content are **never** put in the audit metadata.

---

Live tests against the real webhook
-----------------------------------

[](#live-tests-against-the-real-webhook)

The offline suite uses a fake gateway. To exercise a **real** Discord webhook (`tests/Live`), opt in explicitly — it **posts a real message** to your channel:

```
# .env (or shell env)
REBEL_DISCORD_LIVE=1
DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/123.../your-token

vendor/bin/pest --group=live
```

Without `REBEL_DISCORD_LIVE=1` or with no webhook URL, the live test **self-skips**, so `composer test` and external PRs never trigger a post. In CI, supply the URL as a **secret** and set `REBEL_DISCORD_LIVE=1` on a dedicated job.

---

`.env.example`
--------------

[](#envexample)

```
# The Discord incoming-webhook URL (a SECRET — never commit or log it).
DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/123456789012345678/your-webhook-token

# Optional per-message display overrides (empty = use the webhook defaults).
DISCORD_WEBHOOK_USERNAME=Rebel SOC
DISCORD_WEBHOOK_AVATAR_URL=

# Auto-register the Discord delivery channel (needs DISCORD_WEBHOOK_URL).
REBEL_DISCORD_REGISTER=true

# Live tests (opt-in: POSTS A REAL MESSAGE)
REBEL_DISCORD_LIVE=0
```

---

Security notes
--------------

[](#security-notes)

- **Webhook URL is a secret**: anyone with it can post to your channel. It's read from `.env`, never committed, and **never logged** — not even in exceptions (the gateway error reports only the HTTP status code).
- **No exception leakage**: transport/HTTP errors are caught and returned as a generic `provider_error` `DeliveryResult` — your alerting path never throws out.
- **No PII in the audit trail**: the recipient (Discord channel id) is stored only as a keyed HMAC; the message content is not written to audit metadata.
- **Dormant until configured**: with no `DISCORD_WEBHOOK_URL` (or `register_provider=false`) the package installs cleanly and wires nothing.

---

🔋 Vibe coding with batteries included
-------------------------------------

[](#-vibe-coding-with-batteries-included)

This package ships **AI batteries** — so you (and your AI agent) can extend it correctly on the first try:

- **`CLAUDE.md`** — a concise AI working guide (purpose, conventions, architecture, how to extend, Definition of Done). Plain Markdown, so Claude Code, Cursor, Copilot and Codex all read it.
- **`AGENTS.md`** — the agent/workflow contract (branch → PR → CI → tag/release, the gates).
- **`.claude/skills/`** — invocable skills (at least `rebel-package-dev`) encoding the suite's TDD loop, the **PHPStan-level-max** recipes, the security/telemetry rules, and the release discipline.

Open the repo in your AI editor and just start — the rules, guardrails and extension recipes come with it. PRs that follow the shipped `CLAUDE.md` pass CI (PHPStan max + Pest + Pint) and review the first time around.

Testing &amp; License
---------------------

[](#testing--license)

```
composer test      # Pest (delivery channel + gateway + registration; live suite self-skips)
composer phpstan   # static analysis, level max
composer pint      # code style
```

**License:** MIT — see [LICENSE](LICENSE). Part of the [`padosoft/laravel-rebel`](https://github.com/padosoft) suite.

###  Health Score

37

—

LowBetter than 81% of packages

Maintenance91

Actively maintained with recent releases

Popularity4

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity41

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~0 days

Total

2

Last Release

51d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/10467699?v=4)[Lorenzo](/maintainers/lopadova)[@lopadova](https://github.com/lopadova)

---

Top Contributors

[![lopadova](https://avatars.githubusercontent.com/u/10467699?v=4)](https://github.com/lopadova "lopadova (5 commits)")

---

Tags

laravelAuthenticationwebhookalertsdiscordpadosoftsocRebel

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/padosoft-laravel-rebel-channel-discord/health.svg)

```
[![Health](https://phpackages.com/badges/padosoft-laravel-rebel-channel-discord/health.svg)](https://phpackages.com/packages/padosoft-laravel-rebel-channel-discord)
```

###  Alternatives

[defstudio/telegraph

A laravel facade to interact with Telegram Bots

813336.8k3](/packages/defstudio-telegraph)[harris21/laravel-fuse

Circuit breaker for Laravel queue jobs. Protect your workers from cascading failures.

45955.7k](/packages/harris21-laravel-fuse)[rawilk/profile-filament-plugin

Profile &amp; MFA starter kit for filament.

3914.8k](/packages/rawilk-profile-filament-plugin)[masterix21/laravel-licensing

Laravel licensing package with polymorphic assignment to any model, activation keys, expirations/renewals, and seat control via LicenseUsage. Supports offline verification with public-key–signed tokens, a CLI to generate/rotate/revoke keys, and an extensible architecture via config and contracts.

1613.3k4](/packages/masterix21-laravel-licensing)[simplestats-io/laravel-client

Server-side analytics for Laravel that follows the full funnel from visit to registration to payment, attributed to the channel that drove it. Revenue, MRR, churn and ad-spend profit (ROAS/CAC) per channel. GDPR compliant, ad-blocker proof.

5022.6k](/packages/simplestats-io-laravel-client)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
