Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.authforge.cc/llms.txt

Use this file to discover all available pages before exploring further.

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.