Mystic

Integration Guide

How to add Mystic license checks to your own application.

Getting Set Up

No signup page for app IDs — just DM @decamped on Discord and you'll get one.

How It Works

  1. Open a session when your app starts.
  2. First run on a new device, the user confirms once in a browser — after that it's remembered.
  3. Register with a key, or log in if they've already got an account.
  4. Keep checking in while it runs, so a ban or expired key takes effect right away.

Code Samples

Pick a language for a full example.

import hashlib, hmac, json, os, time, urllib.request, webbrowser

BASE_URL = "https://mysticbin.xyz"
APP_ID = "app_xxxxxxxxxxxxxxxx"

def sha256_hex(s: str) -> str:
    return hashlib.sha256(s.encode()).hexdigest()

def call(path, body, session_id="none", session_token=None):
    payload = json.dumps(body).encode()
    headers = {"Content-Type": "application/json", "X-App-Id": APP_ID}
    if session_token:
        ts = str(int(time.time()))
        nonce = os.urandom(16).hex()
        canonical = "\n".join(["POST", path, ts, nonce, session_id, payload.decode()])
        key = sha256_hex(session_token)
        sig = hmac.new(key.encode(), canonical.encode(), hashlib.sha256).hexdigest()
        headers.update({"X-Session-Id": session_id, "X-Timestamp": ts,
                         "X-Nonce": nonce, "X-Signature": sig})
    req = urllib.request.Request(BASE_URL + path, data=payload, headers=headers, method="POST")
    with urllib.request.urlopen(req) as resp:
        return json.loads(resp.read())

hwid = sha256_hex("this-machine")

# open a session
init = call("/session/init", {"hwid": hwid})
session_id, session_token = init["session_id"], init["session_token"]

# new device - confirm once in a browser and wait
if not init["browser_verified"]:
    webbrowser.open(init["verify_url"])
    while True:
        poll = call("/session/browser-verified",
                     {"challenge_token": init["challenge_token"]}, session_id, session_token)
        if poll["verified"]:
            break
        time.sleep(2)

# solve the captcha, log in
cap = json.loads(urllib.request.urlopen(BASE_URL + "/auth/captcha").read())
a, b = (int(x) for x in cap["question"].split(" + "))
login = call("/auth/login", {
    "username": "player1", "password_hash": sha256_hex("their-password"), "hwid": hwid,
    "captcha_token": cap["token"], "captcha_answer": a + b,
}, session_id, session_token)
user_token = login["user_token"]

# heartbeat, keep this running
call("/auth/validate", {"user_token": user_token, "hwid": hwid}, session_id, session_token)

Client Endpoints

Calls your application makes directly.

EndpointPurposeBrowser Verified
POST /session/initOpen a session for this run; pass a hwid to enable device trustNo
POST /session/browser-verifiedPoll the one-time browser confirmation resultNo
GET /auth/captchaFetch a simple math captcha for login/registerNo
POST /auth/registerRedeem a license key and create an accountYes
POST /auth/loginLog in on the current deviceYes
POST /auth/validateHeartbeat: extend the session, confirm the license is still validNo
POST /auth/logoutEnd the current sessionNo
POST /auth/upgradeRedeem another key onto the current accountYes
POST /auth/change-usernameRename the current accountYes
POST /me/accountRead the current user/license/device summaryNo
POST /me/setvarSet the current user's saved variableYes
POST /me/getvarRead the current user's saved variableYes
POST /app/varRead a global app variableNo
POST /app/statsRead public app statsNo
POST /files/fetchDownload a protected file/blobYes