A Rust replacement for Blizzard's Battle.net account services, built for the digital preservation of retired World of Warcraft Classic client builds.
The Tavern lets you run your own account and authentication server so that abandoned WoW Classic clients can still log in and play. It targets the Classic re-release client lines — Vanilla, The Burning Crusade, Wrath of the Lich King, and Cataclysm Classic — up to defined build cutoffs (see Supported Client Builds).
The Tavern is part of the wowemulation-dev collection of free and open-source World of Warcraft server components. It is independent of, and not affiliated with, Blizzard Entertainment.
Status: Actively developed. Three runnable services: br>
oauth-server,account-server, andbgs-server. The protocol surface br> (browser login, game-client login, OAuth/OIDC, BGS v1/v2 transport, desktop br> app SSO) is functional. Seedocs/plan.md.
Tavern's preservation target is the set of World of Warcraft Classic client builds listed below. All builds in each line, up to and including the cutoff, are in scope; later builds and other client lines are not.
| Client line | Recreates | Build cutoff |
|---|---|---|
| 1.13.x (2019 to 2021) | Vanilla, 2005 (v1.12) | 39692 |
| 1.14.x (2021 to 2023) | Vanilla, 2005 (v1.12) | 51535 |
| 2.5.x through 2.5.4 | The Burning Crusade, 2007 | 44833 |
| 3.4.x through 3.4.4 | Wrath of the Lich King, 2008 | 61581 |
| 4.4.x through 4.4.2 | Cataclysm, 2010 | 60895 |
Build numbers are the values reported by the client at its login screen and catalogued at warcraft.wiki.gg.
The Tavern exists to keep the retired client builds listed above playable. These builds, as originally released, have been superseded by Blizzard's current live offerings; the Tavern preserves them.
The Tavern does not target, and is not intended for use with:
- Any build above the cutoffs listed in Supported Client Builds.
- Any client version Blizzard currently serves. As of June 2026, that includes Classic Era (1.15.x), the Wrath-based Titan Reforged service (3.80.x), Mists of Pandaria Classic (5.5.x), the Burning Crusade Classic Anniversary Edition (2.5.5), and retail World of Warcraft / Midnight (12.0.x).
- Live Blizzard services or any environment where Blizzard currently provides authentication.
The intent is preservation of retired client builds, not circumvention of any active commercial offering.
The Tavern provides three services that replace the Battle.net account, authentication, and BGS-transport surfaces. All three share one Postgres account database.
- Discovery document (
/.well-known/openid-configuration) - RS256 JWT signing with JWKS endpoint
- Authorization code flow with PKCE
- Refresh token rotation
- Client credentials grant (Basic auth)
- RFC 8693 token-exchange for the Battle.net desktop app
POST /ssoclient_ssogrant (Phoenix SSO)- Device authorization grant (RFC 8628)
- Token introspection and userinfo endpoints
- Wire format validated against real Battle.net captures
- Browser SRP6a login: two-step form-encoded (
POST /login/{locale}/+/login/{locale}/password), SSO cookies (login.key,opt,SESSIONID) - Game-client bnet login:
LoginFormenvelope with dual proof schemes — BnetSRP6v2 (TBC/WotLK/Cata) and plaintextsha_pass_hash(Vanilla 1.13/1.14) - Account registration: multi-step wizard with CSRF protection
- Session management: SESSIONID cookie (HttpOnly), XSRF-TOKEN double-submit
- Management API (
/api/*): user profile, game accounts, environment config - SPA dashboard: client-rendered UI, server-rendered login/creation forms
- Dual protocol: BGS v1 (raw TCP, port 1119) for 1.13.x, WebSocket BGS v2 (port 8119) for 1.14.x+ and desktop app
- Auto-detection: v2 service hashes detected on first dispatch frame
- Binary RPC framing: 2-byte BE header size + protobuf Header + body
- Service dispatch: ConnectionService (Connect/ForceDisconnect), AuthenticationService (Logon/VerifyWebCredentials/GenerateSSOToken), GameUtilitiesService (realm list, character count), AccountService
- ForceDisconnect: session-duplicate (57) and server-shutdown (86) error
codes with
DisconnectNotificationbody - Login queue: FIFO dequeue with periodic position updates (both protocol versions)
- Per-account sessions: DashMap tracking, auto-kick on duplicate login
- Graceful shutdown: SIGTERM handler broadcasts ForceDisconnect, drains connections, flushes metrics
- OpenTelemetry metrics exported via OTLP/HTTP (request count/duration, SRP timing, DB pool usage)
- Kubernetes health probes (
/health,/ready,/startup) - DashMap concurrency (lock-free session/challenge maps, ~26% throughput improvement)
tokio::task::spawn_blockingfor 2048-bit SRP modular exponentiation- Configurable DB pool with
DB_POOL_MAX_CONNECTIONSenv var - In-memory map eviction: background reaper (60s) for expired entries
- Per-email rate limiting on SRP challenges
- Admission control via tokio Semaphore with 503 on overload
uv-managed Python project inload-test/bgs-client.py: end-to-end BGS test client (logon, restore, character flow)bgs-queue-test.py: concurrent login queue stress testlogin-harness.py: SRP login load test with latency percentilesseed-loadtest-accounts.py: mass account generator for scale testingdev/srp_auth_client.py: end-to-end SRP auth test
- Game world, realm emulation, and gameplay systems xPm
- Any client version Blizzard currently serves, or any build above the supported cutoffs
Tavern runs three services sharing one Postgres account database:
oauth-serveratoauth.wowemu.dev— OAuth/OIDC endpoints. Access tokens are RS256 JWTs. Refresh tokens are opaque and stored.account-serverataccount.wowemu.dev— Browser login, game-client bnet login, account registration, management API, and the dashboard SPA.bgs-server(BGS v1/v2 transport) — WebSocket RPC for the desktop app and Agent-driven logins, plus raw TCP for 1.13.x game clients.
- Language: Rust (stable, edition 2024).
- Toolchain management: mise.
- Linting:
cargo clippyand the configured markdownlint rules.
Prerequisites are installed with mise:
mise install
# Python test tools additionally need uv
uv sync --directory load-testTavern needs a PostgreSQL 16 database for development and tests. The
dev/db.sh wrapper runs Postgres 16 in a podman container with a fixed
user, password, and database, persisted in a named volume.
bash dev/db.sh up # create + start the tavern-db container (first run)
podman start tavern-db # start it again after a rebootThe container is tavern-db, bound to 127.0.0.1:5432. The default
connection is postgres://tavern:tavern@localhost:5432/tavern.
All dev/db.sh subcommands:
| Command | Effect |
|---|---|
up |
Create and start the container (creates the volume on first run). |
down |
Stop and remove the container; the data volume is retained. |
reset |
down, delete the volume, then up — a fresh database. |
logs |
Tail the last 50 container log lines. |
psql |
Open a psql shell as the tavern user. |
docker is API-compatible with podman; the project standardizes on
podman. Migrations run automatically on server startup. To apply them
before compiling against a fresh database (the sqlx::query! macros check
the schema at compile time), run:
DATABASE_URL=postgres://tavern:tavern@localhost:5432/tavern \
cargo sqlx migrate run --source crates/tavern-db/migrationsRun the servers:
# OAuth provider (oauth.wowemu.dev) — issuer must match BIND_ADDR
DATABASE_URL=postgres://tavern:tavern@localhost:5432/tavern \
BIND_ADDR=127.0.0.1:8081 ISSUER_URL=http://127.0.0.1:8081 \
cargo run -p oauth-server
# Account service (account.wowemu.dev) — INSECURE_COOKIES for local HTTP
INSECURE_COOKIES=1 DATABASE_URL=postgres://tavern:tavern@localhost:5432/tavern \
cargo run -p account-server
# BGS transport (default 127.0.0.1:8119; no database needed)
cargo run -p bgs-serveroauth-server and account-server need DATABASE_URL and run migrations on
startup. bgs-server is stateless (sessions held in memory) and does not.
The oauth-server ships with a demo signing key at keys/signing.pem.
It logs a warning if used in production — see keys/README.md for how
to generate a production key.
Run tests and lint:
DATABASE_URL=postgres://tavern:tavern@localhost:5432/tavern cargo test --workspace
cargo clippy --workspace --all-targets -- -D warningsIntegration tests require a live database (they connect via DATABASE_URL
and run migrations on startup). Unit tests in tavern-core do not.
sqlx::query! calls are checked against .sqlx/ (the offline query cache,
gitignored and regenerated locally). After changing a query or the schema,
regenerate it against the running database, then commit the result:
DATABASE_URL=postgres://tavern:tavern@localhost:5432/tavern \
cargo sqlx prepare --workspaceFor implementation details, see the documentation:
This project is for educational and preservation purposes, and licensed under the terms of the Affero General Public License, version 3.0 or later.
LICENSE.md contains the full license text along with your rights and duties.
Note: This project is not affiliated with Blizzard Entertainment. It is an independent implementation based on reverse engineering by the World of Warcraft emulation community.