$ guides / discord-bot

Discord Bot

Implement Discord user-based licensing with AuthForge using HWID override.

Guide

This pattern binds licenses to Discord users by setting hwidOverride = discord:<user_id>.

Architecture

  1. User runs a slash command (for example /license activate).
  2. Bot asks for key via ephemeral response or DM.
  3. Bot validates with AuthForge using override identity discord:<user_id>.
  4. On success, bot stores entitlement state and unlocks premium commands.

Why this works

  • Discord user IDs are stable and immutable for the account.
  • AuthForge seat limits and reset behavior remain unchanged.
  • You get user-identity licensing without pretending a Discord bot has a real machine HWID.

Use user_id, not usernames or display names.

Use heartbeatMode: "LOCAL" for the bot process. Server heartbeat mode is for apps installed on the end user’s machine that periodically call AuthForge; a Discord bot only needs to validate keys and enforce session expiry on your server, not mirror an end-user “online” heartbeat model.

For cron jobs, per-message handlers, or any path that re-checks the license often, prefer validateLicense (or the equivalent in your language: validate_license, ValidateLicense, validate_license, etc.). It performs the same /auth/validate request and signature verification as login, but does not start heartbeat timers and does not require logout() to clean up background work. One-time startup flows can still use login if you want a long-lived session plus LOCAL heartbeats.

Node example (discord.js-style pseudocode)

import { AuthForgeClient } from "@authforgecc/sdk";

async function validateDiscordKey(discordUserId, licenseKey) {
  const client = new AuthForgeClient({
    appId: process.env.AUTHFORGE_APP_ID,
    appSecret: process.env.AUTHFORGE_APP_SECRET,
    publicKey: process.env.AUTHFORGE_PUBLIC_KEY,
    heartbeatMode: "LOCAL",
    hwidOverride: `discord:${discordUserId}`,
  });

  const result = await client.validateLicense(licenseKey);
  if (!result.valid) {
    return { ok: false, code: result.code };
  }
  return { ok: true, appVariables: result.appVariables, licenseVariables: result.licenseVariables };
}

Operational recommendations

  • Use ephemeral responses or DMs to avoid exposing keys in channels.
  • Rate limit invalid attempts to reduce brute force.
  • Use maxHwidSlots=1 for strict per-user license behavior.
  • Document how users can request resets if they change accounts.

Contact support

Feel free to reach out if you have questions, need help getting set up, or run into something unexpected. We'll get back to you as soon as we can.

Email us at support@authforge.cc