> ## 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.

# Discord Bot

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

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)

```javascript theme={null}
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.

## Related

* [HWID override](/features/hwid-override)
* [HWID Override Guide](/guides/hwid-override)
* [Security lists](/features/security)
