Skip to main content
PathMon

Chapter 1 of 6

Discord Notifications

Updated Read the full guide

PatchMon integrates with Discord in two separate, independent ways:

  1. Discord OAuth2 login: let users sign in to PatchMon with their Discord account, or link an existing PatchMon account to a Discord identity. Configured under Settings → Discord Auth.
  2. Discord as a notification / alert destination: fire PatchMon alerts and scheduled reports into a Discord channel via an incoming webhook. Configured under Settings → Alert Channels as a webhook destination.

You can enable either, both, or neither. They don't depend on each other.

Related pages:

  • Users, Roles and RBAC: manage roles and account linking
  • Setting Up OIDC / Single Sign-On: an alternative way to delegate login to an external IdP

Part 1: Discord OAuth2 Login

Let users authenticate to PatchMon with their Discord account. PatchMon supports three related flows:

  • Sign in with Discord (for users who don't yet exist): auto-creates a PatchMon account if self-registration is enabled.
  • Sign in with Discord (for users who do exist): auto-links by matching the verified Discord email to the user's PatchMon email.
  • Link Discord to an existing logged-in account: from the Profile page, attach a Discord identity to your PatchMon account without changing your password.

Everything is configured through the Settings UI. No environment variables are required; secrets are stored encrypted in the PatchMon database.

What you'll end up with

  • An additional Login with Discord button on the PatchMon login page.
  • Optional automatic account creation on first Discord login (driven by the PatchMon signup setting).
  • A Discord avatar and username visible on each user's profile.

Before you begin

You need:

Item Notes
A running PatchMon instance Reachable at a fixed URL, e.g. https://patchmon.example.com
HTTPS on the PatchMon URL Discord requires https:// redirect URIs in production
A PatchMon admin account with can_manage_settings To reach the Discord Auth settings page
A Discord account To access the Discord Developer Portal

Step 1: Find your callback URL

The callback is derived from PatchMon's configured server URL and is shown to you on the settings screen, but for reference the canonical path is:

https://patchmon.example.com/api/v1/auth/discord/callback

If PatchMon is showing the wrong hostname (for example http://localhost:3000 when you're running in production), fix your Server URL in Settings → Server Config first. The callback URL is read-only in the Discord settings panel and is rebuilt from the server URL whenever you save.

Step 2: Create a Discord application

  1. Go to the Discord Developer Portal.

  2. Click New Application and give it a name (e.g. PatchMon).

  3. In the left menu, open OAuth2.

  4. Under Redirects, click Add Redirect and paste your callback URL:

    https://patchmon.example.com/api/v1/auth/discord/callback
    
  5. Click Save Changes at the bottom.

  6. Copy the Client ID (shown at the top). You'll paste it into PatchMon in the next step.

  7. Click Reset Secret (or Copy if the secret is already visible), and save the value. Discord will only show this once. If you lose it, you'll have to reset it again.

You do not need to set up an OAuth2 URL / redirect URL generator in Discord. PatchMon builds the authorisation URL itself. The only field that matters in the Discord UI is the Redirects list.

Step 3: Configure PatchMon

  1. Sign in to PatchMon as an admin.
  2. Go to Settings → Discord Auth.
  3. Fill in the OAuth2 Configuration panel:
    • Client ID: the Application ID from Discord's app overview.
    • Client Secret: paste the secret from Step 2 into the field and click Save. The Not set badge should flip to Set (green tick). PatchMon encrypts the secret at rest using its configured SECRET_ENCRYPTION_KEY.
    • Redirect URI: usually leave blank. PatchMon derives the callback from the server URL automatically. Only override if you're behind a proxy that presents a different public URL.
    • Button Text: customise the login button label, e.g. Sign in with Discord. Defaults to Login with Discord.
  4. Click Apply to save the text fields.
  5. At the top of the panel, flip Enable Discord OAuth to on.

Step 4: Test

  1. Open PatchMon in a private / incognito browser window.
  2. On the login page you should now see a Login with Discord (or your custom label) button.
  3. Click it. Discord will ask you to authorise the PatchMon application.
  4. Accept. You'll be redirected back to PatchMon.

First-login behaviour

  • If a PatchMon user with the same email already exists and the Discord email is verified, PatchMon automatically links the accounts. You're logged in.
  • If no PatchMon user exists and self-registration is on (Settings → Users → User Registration Settings → Enable User Self-Registration), PatchMon creates a new account with:
    • Username: derived from the Discord username, stripped of unsafe characters, with a numeric suffix if the base name collides.
    • Email: the Discord email (or discord_<id>@discord.local if Discord doesn't expose an email).
    • Role: the Default Role for New Users setting.
  • If no PatchMon user exists and self-registration is off, the login flow redirects to /login?error=User+not+found. An admin must create the account first; next time, the verified-email auto-link kicks in.

Linking Discord to an existing PatchMon account

This is the safer alternative to "Sign in with Discord" for users who already have a PatchMon account. It lets them keep their username / email / password workflow and just adds a Discord badge.

  1. User signs in to PatchMon as normal.
  2. Clicks their avatar → Profile.
  3. Scrolls to the Linked Accounts section and clicks Link Discord.
  4. PatchMon redirects them to Discord to authorise, then back to the profile page.
  5. On success, the profile shows the Discord username and avatar, and a small "discord_linked=true" success banner.

Unlinking

Same panel → Unlink Discord. PatchMon refuses to unlink if Discord is the user's only login method (no password set, no OIDC linked), as this would lock the user out. Set a password in the Change Password panel first, then retry the unlink.

Troubleshooting: OAuth login

The "Login with Discord" button doesn't appear on the login page

  • Toggle is off. Check Settings → Discord Auth → Enable Discord OAuth.
  • Client secret is missing. The badge next to the field should say Set. If it says Not set, paste the secret and click Save.
  • Client ID is blank. Check the same panel; the Client ID field must be populated.

Redirect error: "The redirect URI isn't registered"

The URL Discord is being asked to redirect to doesn't match anything in the Discord app's Redirects list.

  • In Discord's Developer Portal, open your app → OAuth2Redirects and make sure https://patchmon.example.com/api/v1/auth/discord/callback is listed exactly. The protocol (https://), host, port, and path must all match.
  • Don't include a trailing slash; don't include query strings.
  • If PatchMon is behind a reverse proxy, make sure PatchMon's Server URL reflects the public URL, not the internal one.

Error: "Discord is not fully configured"

One of Client ID or Client Secret is missing. Fill them both in, then click Apply and Save respectively.

Error: "Already linked" when linking

Someone else in PatchMon is already linked to that Discord account. Only one PatchMon user can hold a given Discord identity at a time.

First-login auto-create didn't happen

Auto-create only runs when Settings → Users → User Registration Settings → Enable User Self-Registration is on. If it's off, pre-create the user (with a matching email) and try again.


Part 2: Discord as a Notification / Alert Destination

PatchMon can push alerts, events and scheduled reports to a Discord channel via an incoming webhook (Discord's built-in mechanism for posting into a channel from an external service). This is handled by the generic "webhook" alert channel. PatchMon detects Discord URLs automatically and formats the message as a Discord embed.

What you'll end up with

  • A Discord channel that receives rich embedded messages for every PatchMon event of the type(s) you've subscribed.
  • Colour-coded severity (critical = red, error = orange, warning = yellow, informational = blue).
  • Structured fields based on the event type (container stops, host down, user role changes, etc.).
  • Scheduled reports (daily / weekly / monthly summaries) also delivered as embeds, with a plain-text excerpt and CSV attached where supported.

Step 1: Create a Discord incoming webhook

  1. In Discord, open the server (guild) that owns the target channel.

  2. Server settings → IntegrationsWebhooksNew Webhook.

  3. Give the webhook a name (e.g. PatchMon), pick the target channel, optionally set an avatar.

  4. Click Copy Webhook URL. You should now have a URL shaped like:

    https://discord.com/api/webhooks/1234567890/abcdefgh-ABCDEFGH1234567890
    

    Keep it safe. Anyone who holds this URL can post to your channel.

Step 2: Add the webhook to PatchMon

  1. Sign in to PatchMon with a role that has can_manage_notifications.
  2. Go to Settings → Alert Channels.
  3. Click Add Destination.
  4. Pick Webhook as the channel type.
  5. Fill in:
    • Display Name: e.g. Ops Discord. Any label that helps you identify the channel later.
    • Webhook URL: paste the Discord webhook URL from Step 1.
  6. PatchMon detects it is a Discord URL automatically (the UI shows "Discord and Slack URLs are auto-detected for rich formatting"). Nothing else to configure for Discord.
  7. Click Save.

Heads-up: Anything else that starts with https://discord.com/api/webhooks/, https://discordapp.com/api/webhooks/, or https://www.discord.com/api/webhooks/ is treated as Discord and formatted with embeds. Slack URLs are detected similarly. Everything else is sent as a plain JSON {"title":..., "message":..., "severity":...} POST, which you can consume with your own handler.

Step 3: Route alerts to the destination

Creating the destination does not automatically route any events to it. You need at least one routing rule.

  1. Still on Settings → Alert Channels, scroll to the Routing Rules section.
  2. Click Add Rule.
  3. Pick the destination you just created from the dropdown.
  4. Choose the events / severities you want to send. The recommended starter set:
    • host_went_down
    • host_came_up
    • container_stopped
    • security_updates_available
    • user_tfa_disabled
    • account_locked
  5. Save the rule.

Your Discord channel should start receiving notifications on the next matching event. To test quickly, simulate a host-down event by stopping the PatchMon agent on any non-critical host and waiting for the next check-in cycle.

Step 4 (optional): Route scheduled reports

Alongside real-time alerts, PatchMon can send a periodic summary report to the same webhook.

  1. On the Alert Channels page, scroll to Scheduled Reports.
  2. Click Add Schedule.
  3. Configure:
    • Destinations: tick your Discord webhook.
    • Frequency: daily, weekdays, weekly (pick days), or monthly (pick day or "last day").
    • Delivery time: hour and minute in your server's timezone.
    • Sections: which report sections to include (Open alerts, Hosts by outstanding updates, Top outdated security packages).
  4. Save.

For Discord delivery, scheduled reports are rendered as:

  • A title with the report subject.
  • A short plain-text excerpt of the HTML body (tags stripped).
  • A PatchMon footer.
  • If a CSV attachment is configured, it is posted as a separate file via Discord's multipart upload.

Message format

Real-time alerts

Each event becomes a Discord embed:

  • Title: the event title (e.g. Host Down: web01.example.com).
  • Description: the full event message.
  • Colour: derived from severity (critical red, error orange, warning yellow, informational blue, everything else grey).
  • Fields: structured fields per event type (e.g. for container_stopped: host name, container name, image, old status, new status).
  • Footer: PatchMon.

Scheduled reports

  • Title: report subject line.
  • Description: excerpt of the HTML body, with tags (including <script> blocks) stripped.
  • Footer: PatchMon.

Troubleshooting: Notifications

Webhook URL shows "Webhook URL is required"

The form rejected an empty URL. Paste the full Discord webhook URL you copied in Step 1.

Destination saved but no Discord messages arrive

Walk through this list in order:

  1. Did any matching event fire? Check Alerts → Notification Logs. If the log shows no rows for your destination, no events matched your routing rules. Adjust the rules.

  2. Does the log show a failure? Filter the log by destination. If the delivery attempt failed, hover over the row to see the error Discord returned. Common ones:

    • 401 or 404: the webhook has been deleted in Discord. Re-create it and update the URL.
    • 429 Too Many Requests: you're hitting Discord's rate limit. Reduce the event volume, or split across multiple webhooks / channels.
  3. Did PatchMon even try? Check the PatchMon server logs:

    # Docker
    docker compose logs patchmon-server | grep -i notification
    
  4. Is the URL actually Discord? PatchMon only formats as an embed when the URL hostname is discord.com, discordapp.com, or www.discord.com and the path contains /api/webhooks/. A typo in the URL (e.g. discord.co or no /api/ segment) falls back to the generic JSON POST format, which Discord will reject. Confirm the URL contains /api/webhooks/.

Posts are plain text, not embeds

The URL is not being recognised as Discord. See the last point above and verify the exact hostname and path.

Everything works but messages are posted to the wrong channel

The webhook URL encodes the target channel. In Discord, go to server settings → IntegrationsWebhooks, select the webhook, and change Channel. Alternatively, create a new webhook for the correct channel and update PatchMon to use it.

I want to remove the webhook cleanly

  1. In PatchMon, Settings → Alert Channels, find the destination, click Delete.
  2. In Discord, server settings → IntegrationsWebhooks, find the webhook, click Delete Webhook. This is the reliable way to revoke. Deleting only in PatchMon leaves the URL live; if anyone else captured the URL they can still post to your channel.

Security notes

OAuth login

  • The Discord Client Secret is stored encrypted in the PatchMon database using the server's SECRET_ENCRYPTION_KEY. Make sure that environment variable is set and is not the default value in production.
  • Account linking by email is only performed when Discord reports the user's email as verified, to prevent account takeover via an unverified email address.
  • PatchMon uses PKCE (S256) for Discord OAuth2 code exchange, so the authorisation code can't be replayed even if intercepted.
  • The Discord OAuth state is tied to a short-lived (10-minute) session stored in Redis; it's one-time-use and bound to an HttpOnly discord_state cookie.

Webhooks

  • Discord webhook URLs are bearer tokens. Anyone with the URL can post to your channel. Treat the webhook URL like a password.
  • PatchMon stores webhook URLs encrypted at rest if a SECRET_ENCRYPTION_KEY is configured. Without one, URLs are stored in plaintext. Don't skip setting the encryption key.
  • Do not paste webhook URLs into public GitHub issues, screenshots, or chat channels.
  • Consider creating a dedicated Discord channel and webhook per PatchMon environment (prod / staging) so you can revoke them independently.

Quick reference

Task Where
Create / edit Discord OAuth app Discord Developer Portal
Enable Discord login in PatchMon Settings → Discord Auth
Sign in via Discord Login page → Login with Discord button
Link existing account to Discord Profile → Linked Accounts → Link Discord
Create Discord webhook Server → Settings → Integrations → Webhooks
Add webhook to PatchMon Settings → Alert Channels → Add Destination → Webhook
Route events to Discord Settings → Alert Channels → Routing Rules
Schedule summary reports to Discord Settings → Alert Channels → Scheduled Reports
Check delivery history Alerts → Notification Logs