Skip to main content

Reference Client

Vampauth ships a Luau reference client. It posts to key/check, verifies the Ed25519 signature inside the executor, and only reports success when the response is genuine. A thin wrapper handles the request, nonce, and signature gates; the crypto core (Ed25519, SHA-256, SHA-512, Base64 — adapted from rbx-cryptography, MIT) is fetched separately and verified against a pinned SHA-256 digest before it is trusted. Nothing is hand-rolled in the security-critical code.

What it does

Check(key) returns true, payload only when every gate passes:
  • the request returned 2xx,
  • nonce_echo matches the nonce this call sent,
  • the response carries signature and project_id,
  • the Ed25519 signature verifies over sha256(nonce|hwid|expiresAtUnix|project_id),
  • and the key is not locally expired.
Any failure returns false, reason. Nothing runs on a fail-closed path.
Not secure out of the box. The client verifies the server’s signature only; it does not stop anyone editing or deleting the gate in your script. Embed it and obfuscate the whole script before shipping. The default HWID is basic — pass your own fingerprint for real binding.
On success the client also caches the full response in Vampauth:State() under VAMP_* keys — VAMP_STATUS, VAMP_KEY, VAMP_EXPIRES_AT, VAMP_CREATED_AT, VAMP_DISCORD_ID, VAMP_DISCORD_USERNAME, VAMP_IS_PREMIUM, and VAMP_HWID_BOUND. VAMP_REASON is "Key validation". Because the key maps read-through, fields the API does not yet populate (e.g. Discord identity for plain keys) are nil/false.

Crypto core

The wrapper is intentionally thin. Ed25519 verification, SHA-256/SHA-512, and Base64 live in a separate crypto core that the wrapper fetches on first use from https://vampauth.com/client/vampauth-crypto.lua. Before that code runs, the wrapper computes its SHA-256 and compares it to a digest pinned into the wrapper at build time — a tampered or replaced core is rejected with false, "crypto mismatch". The core is public MIT math (no secrets), so the wrapper is the only piece you must obfuscate along with your script. The crypto core is also cached on the executor environment (getgenv().VampauthCrypto) and can be supplied explicitly via Check(key, { crypto = myCryptoTable }), so a loader can fetch it once and share it across many embedded clients.

Executor support (UNC-style)

HttpFetch tries request, then http_request, then syn.request, and falls back to HttpService:RequestAsync; it reads both StatusCode/statusCode and Body/body forms. HWID helpers use getgenv (falling back to _G) and, when present, readfile/writefile. The client runs on any executor that exposes the standard UNC surface.

Configuration

The default HWID is the Roblox analytics client id — a per-install string, not a strong unique. The client uses it as the default fingerprint, falling back to a persisted file (when the executor has readfile/writefile) and then a fresh per-session id. Do not rely on it for real binding; pass your own fingerprint via Vampauth.new({ hwid = ... }) / SetHWID(...). For a stronger fingerprint see Integration snippets.

Embed, then obfuscate

The recommended workflow:
  1. Embed the client inside your script (paste the module body, not a remote loadstring).
  2. Embed your keycheck logic, project key, and public signing key in the same file.
  3. Obfuscate the whole thing with script protection.
Never serve the module standalone from a readable URL — a shared module fetched over HTTP is the one place it is easy to patch out. Once it is obfuscated together with your script, removing the check means defeating the obfuscation.

Threat model

What verifying the signature stops:
  • Fake responses — a malicious server or an injected HTTP hook cannot sign a response; only Vampauth holds the project’s signing private key.
  • Replays — each call uses a fresh nonce, so a captured valid response no longer verifies on the next call.
  • Edited responses — changing expires_at or key invalidates the signature.
What it does not stop:
  • The user removing the check — a client executed locally can have the keycheck patched out. This is what obfuscation is for.
  • Weak HWID fingerprints — HWID is passthrough; Vampauth only compares the string. The default (analytics client id) is basic; real binding requires your own fingerprint via SetHWID.
  • Replacing the crypto core only — the digest pin blocks swapped crypto, but this stops the wrapper, not your whole script. Obfuscating the wrapper with your script is still the real defense.

Source

The wrapper lives at sdk/reference/wrapper.luau in the repository and builds to sdk/reference/vampauth.lua (sdk/reference/vampauth-crypto.lua for the crypto core). Both are served to in-game clients from /client/vampauth.lua and /client/vampauth-crypto.lua. The wrapper is verified on the real-luau Delta executor (sdk/vampauth-delta-test.lua); scripts/verify-reference-client.js is a smoke harness.

See also