Files
autoreg-skills-max/skills/bulk-account-registration/references/steam-autoreg.md

7.6 KiB

Steam Account Registration — Platform-Specific Techniques

Extends the bulk-account-registration pipeline with Steam-specific flows. Covers the full lifecycle: form submission → reCAPTCHA v2 → email verification → Steam Guard activation.

Key Differences from Generic Registration

Steam is NOT a typical REST API registration. It's a multi-step web form with:

  • reCAPTCHA v2 (not Turnstile — use RecaptchaV2TaskProxyless on 2captcha)
  • AJAX email availability check before form submission (/join/ajaxverifyemail)
  • RSA-encrypted password submission for login (not for registration itself)
  • Email verification code (5-char alphanumeric, NOT numeric)
  • Optional Steam Guard mobile authenticator activation via ITwoFactorService

Flow Overview

GET /join/ → extract sessionid cookie
    ↓
2captcha: solve reCAPTCHA v2 (sitekey: 6LdIFr0Z...)
    ↓
POST /join/ajaxverifyemail  → check email availability
    ↓
POST /join/createaccount    → submit form with g-recaptcha-response
    ↓
Poll email (IMAP/GuerrillaMail) → extract 5-char Steam Guard code
    ↓
(Optional) POST /steamguard/add_ajax → activate mobile authenticator
    ↓
(Optional) ITwoFactorService/AddAuthenticator → extract shared_secret

reCAPTCHA v2 on Steam

Steam uses reCAPTCHA v2 (checkbox), NOT Turnstile and NOT invisible reCAPTCHA.

Sitekey: 6LdIFr0ZAAAAAO3vz0O0OQOyjusTBucR2cwXTO4n Page URL: https://store.steampowered.com/join/

2captcha solve (via createTask API, not legacy in.php):

payload = {
    "clientKey": "YOUR_2CAPTCHA_KEY",
    "task": {
        "type": "RecaptchaV2TaskProxyless",
        "websiteURL": "https://store.steampowered.com/join/",
        "websiteKey": "6LdIFr0ZAAAAAO3vz0O0OQOyjusTBucR2cwXTO4n",
        "isInvisible": False,
    }
}
# POST https://api.2captcha.com/createTask → poll /getTaskResult
# Solution field: solution.gRecaptchaResponse

Difference from Turnstile: Turnstile uses method=turnstile on legacy API with sitekey and pageurl params. reCAPTCHA v2 uses RecaptchaV2TaskProxyless on the createTask JSON API. Do NOT use Turnstile method for Steam — it's reCAPTCHA.

Form Submission Details

Email Availability Check

POST https://store.steampowered.com/join/ajaxverifyemail
Data: email=user@domain.com&sessionid=<sessionid>
Headers: X-Requested-With: XMLHttpRequest, Referer: .../join/
Response: {"bEmailAvailable": true} or false

Account Creation

POST https://store.steampowered.com/join/createaccount
Data:
  accountname=<username>
  password=<password>
  email=<email>
  email_confirm=<email>
  captchagid=-1
  captcha_text=
  iAgree=1
  ticket=
  g-recaptcha-response=<2captcha_token>
  count=7              # country code (7=US)
  l=english
  creation_sessionid=<sessionid>

No RSA encryption needed for registration — that's only for login.

RSA Password Encryption (Login Only)

When logging into an existing account, Steam requires RSA-encrypted passwords:

# 1. Get RSA key
POST https://store.steampowered.com/login/getrsakey/
Data: username=<username>&donotcache=<timestamp_ms>
Response: {"success": true, "publickey_mod": "<hex>", "publickey_exp": "<hex>", "timestamp": "<ts>"}

# 2. Encrypt password (PKCS1 v1.5)
mod = int(publickey_mod, 16)
exp = int(publickey_exp, 16)
pw_int = int.from_bytes(password.encode("utf-8"), "big")
encrypted_int = pow(pw_int, exp, mod)
encrypted_b64 = base64.b64encode(encrypted_int.to_bytes(...))

# 3. Submit login
POST https://store.steampowered.com/login/dologin/
Data: username=...&password=<encrypted_b64>&rsatimestamp=<ts>&emailauth=<code>...

Email Verification Code Extraction

Steam sends a 5-character alphanumeric code (uppercase letters + digits). Pattern:

re.search(r'\b([A-Z0-9]{5})\b', email_body)

The email comes from noreply@steampowered.com with subject containing "Steam Guard".

IMAP search:

client.search(["FROM", "noreply@steampowered.com"])
client.search(["SUBJECT", "Steam Guard"])

GuerrillaMail: Subject line and body both contain the code. The _extract_steam_code() function handles HTML and plain text.

Steam Guard Mobile Authenticator (TOTP)

Steam uses a custom TOTP implementation:

  • Algorithm: HMAC-SHA1
  • Period: 30 seconds
  • Digits: 5
  • Alphabet: 23456789BCDFGHJKMNPQRTVWXY (no 0, 1, A, E, I, O, L, S, U, Z — avoids ambiguous characters)

TOTP Generation

import hmac, hashlib, base64, struct, time

def generate_steam_totp(shared_secret_b64: str, timestamp: int = None) -> str:
    if timestamp is None:
        timestamp = int(time.time())
    secret = [REDACTED])
    time_bytes = struct.pack(">Q", timestamp // 30)
    hmac_result = hmac.new(secret, time_bytes, hashlib.sha1).digest()
    offset = hmac_result[-1] & 0x0F
    code_int = struct.unpack(">I", hmac_result[offset:offset + 4])[0] & 0x7FFFFFFF
    steam_alphabet = "23456789BCDFGHJKMNPQRTVWXY"
    code = ""
    for _ in range(5):
        code += steam_alphabet[code_int % len(steam_alphabet)]
        code_int //= len(steam_alphabet)
    return code

Activating Steam Guard (extracting shared_secret)

Endpoint 1 (community page):

POST https://steamcommunity.com/steamguard/add_ajax
Data: sessionid=...&op=add_authenticator&device_identifier=android:<uuid>&sms_phone_id=1&access_token=
[REDACTED] {"success": true, "shared_secret": "<base64>", "identity_secret": "<base64>", ...}

Endpoint 2 (API — more reliable):

POST https://api.steampowered.com/ITwoFactorService/AddAuthenticator/v0001
Data: steamid=<steamid64>&authenticator_time=<server_time>&authenticator_type=1&device_identifier=<device_id>&sms_phone_id=1

# Then finalize:
POST https://api.steampowered.com/ITwoFactorService/FinalizeAddAuthenticator/v0001
Data: steamid=<steamid64>&authenticator_code=<generated_totp>&authenticator_time=<server_time>&activation_code=

Device ID format: android:XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX (lowercase hex UUID).

Getting server time:

POST https://api.steampowered.com/ITwoFactorService/QueryTime/v0001
Response: {"response": {"server_time": "1719600000"}}

SteamID64 Retrieval

After login, SteamID64 appears in the URL: https://steamcommunity.com/profiles/7656119XXXXXXXXXX/

Or resolve custom URL:

GET https://api.steampowered.com/ISteamUser/ResolveVanityURL/v0001/?key=&vanityurl=<custom>
Response: {"response": {"steamid": "7656119XXXXXXXXXX", "success": 1}}

Pitfalls

  1. Don't use Turnstile method for Steam — it's reCAPTCHA v2. Wrong method = wasted 2captcha balance.
  2. Steam Guard code is 5 chars, NOT 6 — unlike most OTP systems. Regex \d{6} will miss it.
  3. RSA encryption is for LOGIN, not registration — registration submits plaintext password.
  4. sms_phone_id=1 skips SMS — use this to avoid phone verification requirement.
  5. GuerrillaMail domains are blocked by some platforms but NOT Steam — Steam accepts @guerrillamail.com addresses.
  6. Session cookies expire quickly — complete the full flow (register → verify → guard) within 10 minutes or the session dies.
  7. Steam rate-limits registrations per IP — use rotating proxies for batch creation. Minimum 30-90s between accounts from same IP.
  8. Email availability check is mandatory — Steam won't accept the create form without a prior successful ajaxverifyemail call in the same session.

See Also

  • bulk-account-registration — general IMAP, proxy rotation, browser automation patterns
  • references/multi-provider-imap-servers.md — IMAP server routing for reading Steam Guard emails
  • C:\Users\User\steam_registrar\steam_register.py — complete working implementation