LimboAuth is a Minecraft authentication (auth) plugin developed by the Elytrium team that runs on the Velocity proxy. Before sending a player to the real server it puts them into a virtual limbo world, has them complete the /register or /login command there, and then transfers them to the lobby or the main server. Unlike AuthMe, the entire load is handled at the proxy layer, so the backend servers (Paper, Purpur, Folia) are never touched by auth traffic.

What Is LimboAuth?

LimboAuth is part of Elytrium's Limbo ecosystem. The ecosystem consists of three main components:

  • LimboAPI: the virtual world (limbo) engine for Velocity. It can simulate chunks, player entities, blocks and inventories without a Paper/Spigot server. It is LimboAuth's core dependency.
  • LimboAuth: authentication, register/login, TOTP, captcha, session management and database integration.
  • LimboFilter: a front-line filter against bot attacks. It provides IP rate limiting, captcha, login attempt monitoring and protocol-level filtering — it kicks in before LimboAuth.

The main focus of this guide is LimboAuth, but in production it is recommended to use all three together. For cracked (offline-mode) servers in particular, the LimboFilter + LimboAuth combination is a standard protection layer.

Why LimboAuth? — A Comparison with AuthMe and LibreLogin

There are three major auth solutions in the Minecraft ecosystem: AuthMe ReReloaded, LibreLogin and LimboAuth. The choice depends on your server architecture.

FeatureLimboAuthAuthMe ReReloadedLibreLogin
Proxy supportVelocity onlyBukkit/BungeeCord (bridge)Velocity + BungeeCord
Auth layerProxy (limbo)Backend server (Bukkit)Proxy (limbo)
TOTP/2FAYes (built in)Third partyYes (built in)
CaptchaYesYesYes
Premium autologinYesYesYes
Mail recoveryYesYes (MailAPI)Yes
Bot protectionVia LimboFilterRequires an antibot pluginBuilt-in rate limit
LicenceMITGPLv3GPLv3
Recommended scenarioVelocity networkLegacy BukkitVelocity/BungeeCord network

The short verdict: if you are building a new server and using Velocity, go with LimboAuth; if you have an existing AuthMe installation and want to migrate, LibreLogin (it has an easier migration path); if you are running a single Bukkit server only, AuthMe ReReloaded.

How Does LimboAuth Work? — The Architecture

When a player connects to Velocity, the process runs like this:

  • 1. Connection: the player sends a handshake to Velocity. Velocity receives the player.
  • 2. Premium check: if Floodgate is present, Bedrock players are detected. LimboAuth queries the Mojang API to verify the premium UUID (when force_offline_mode=false).
  • 3. Redirect to limbo: LimboAPI sends the player into a virtual world. Only chat and a limited set of commands are active there.
  • 4. Login/Register: if there is a record in the database, /login is requested, otherwise /register. Once it completes, a token is created.
  • 5. Transfer: the player is sent to the first reachable server in the try list (usually the lobby).
  • 6. Session: if they reconnect within a certain period, they are logged in automatically through the IP+UUID match.

System Requirements

  • Java: 17 or newer (21 recommended).
  • Velocity: 3.3.0 or newer (3.4+ is more stable).
  • RAM: an extra 256–512 MB is enough for LimboAPI + LimboAuth; set aside 1 GB for a bot attack scenario.
  • CPU: 1 vCPU is comfortably enough for LimboAuth; 2 vCPU is recommended if LimboFilter is rendering captchas.
  • Database: H2 (testing), MySQL 8.0+ / MariaDB 10.5+ (production), PostgreSQL 13+ (scale), SQLite (small scale).
  • Disk: auth data takes very little space; 100K records ≈ 50 MB. Set aside 1 GB for MySQL.
  • Proxy: ports that need to be open for connections: 25565 (Minecraft), 3306 (MySQL, if it is external).

Installation: LimboAPI and LimboAuth

Both plugins have to be dropped into Velocity's plugins/ folder. LimboAuth depends on LimboAPI; if you get the order wrong, Velocity throws an error on startup.

bash
# Go to the Velocity directory
cd /opt/velocity

# Download LimboAPI (latest release from the GitHub releases page)
wget -O plugins/limboapi.jar \
  https://github.com/Elytrium/LimboAPI/releases/latest/download/limboapi-plugin.jar

# Download LimboAuth
wget -O plugins/limboauth.jar \
  https://github.com/Elytrium/LimboAuth/releases/latest/download/limboauth.jar

# LimboFilter (optional but recommended)
wget -O plugins/limbofilter.jar \
  https://github.com/Elytrium/LimboFilter/releases/latest/download/limbofilter.jar

# Restart Velocity
systemctl restart velocity

On the first start LimboAuth creates config.yml, messages.yml and the default H2 database file under the plugins/limboauth/ directory.

Choosing and Setting Up the Database

LimboAuth supports four database drivers: H2 (default, in-memory + disk), SQLite, MySQL/MariaDB and PostgreSQL. For production, prefer MySQL or PostgreSQL.

MySQL / MariaDB Setup

sql
-- Create the database and user in MySQL
CREATE DATABASE limboauth CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'limboauth'@'localhost' IDENTIFIED BY 'StrongPassword2026!';
GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, ALTER, INDEX ON limboauth.* TO 'limboauth'@'localhost';
FLUSH PRIVILEGES;

Update the storage block inside config.yml as follows:

yaml
database:
  storage-type: "mysql"
  hostname: "127.0.0.1:3306"
  user: "limboauth"
  password: "StrongPassword2026!"
  database: "limboauth"
  connection-parameters: "?autoReconnect=true&useSSL=false&serverTimezone=UTC"

PostgreSQL Setup

bash
sudo -u postgres psql
CREATE DATABASE limboauth;
CREATE USER limboauth WITH ENCRYPTED PASSWORD 'StrongPassword2026!';
GRANT ALL PRIVILEGES ON DATABASE limboauth TO limboauth;
\q

Basic Configuration (config.yml)

The config.yml generated on first launch is hundreds of lines long. Here we explain the critical parameters section by section. Using the defaults as they are is not acceptable from a security point of view.

The Auth Section

yaml
auth:
  # Minimum and maximum password length
  min-password-length: 8
  max-password-length: 100

  # Should the password be asked twice on registration?
  enable-totp: true
  register-requires-repeat-password: true

  # Time allowed to an unregistered player (seconds)
  auth-time: 60

  # Kick threshold (wrong password attempts)
  login-attempts: 3

  # Registration limit per IP (against bot attacks)
  ip-limit-registrations: 3

  # Taking the same nickname as another player is forbidden
  save-uuid: true

  # Stop the wrong players from claiming premium UUIDs
  save-premium-accounts: true
  check-password-strength: true

The Main (Limbo Server) Section

yaml
main:
  # Virtual coordinates of the limbo world — no need to change these
  world-file-path: "worlds/world.schem"
  world-file-type: "WORLDEDIT_SCHEM"

  # The servers the player will be sent to after login
  auth-coords:
    x: 0.5
    y: 64
    z: 0.5
    yaw: 0
    pitch: 0

  # Which server should they be transferred to on a successful login?
  login-kick-message: "<red>Your session has expired, please log in again."

Separating Premium (Online Mode) and Cracked Players

If you are running Velocity in offline mode (that is, online-mode: false in velocity.toml), LimboAuth can query the Mojang API to check whether a nickname belongs to a premium account. There are two policies:

  • Strict mode (recommended): premium nicknames can only be used by premium players. A cracked player cannot register a premium nickname.
  • Free mode: anyone can use any nickname. The only benefit for premium players is auto-login.
yaml
auth:
  # Protect premium nicknames
  save-premium-accounts: true

  # Do not make premium players register, let them straight in
  force-offline-uuid: false

  # Mojang API cache lifetime (seconds)
  premium-check-cache: 3600

  # What to do if the API is unreachable?
  # "ASSUME_CRACKED" is the safe default; "KICK" is strict mode
  mojang-rate-limit-behavior: "ASSUME_CRACKED"

TOTP / 2FA (Google Authenticator) Configuration

LimboAuth offers RFC 6238 compliant TOTP support. With the /2fa command the player receives a QR code or a 16-character secret key and adds it to Google Authenticator / Authy / Microsoft Authenticator.

yaml
auth:
  enable-totp: true
  totp-issuer: "KEYDAL Network"

  # Require TOTP (recommended for admin groups)
  totp-need-passed-for-admins: true

  # Code validity period
  totp-recovery-codes-amount: 16
  • /2fa — activates TOTP and gives you a QR code
  • /2fa disable [password] — removes 2FA
  • /2fa recovery — generates 16 recovery codes; taking a screenshot is recommended

Captcha Configuration

A captcha system integrated with LimboFilter against bot attacks. While in limbo, the player enters the 5-digit number shown on a map as /captcha [code].

yaml
captcha:
  # Force captcha (recommended)
  need-captcha: true

  # How many captchas per IP per day?
  ip-captcha-limit: 10

  # Captcha duration (seconds)
  captcha-duration: 30

  # Should a new captcha be generated after a wrong answer?
  regen-on-wrong: true

  # Visual quality
  captcha-length: 5
  render-font: "DroidSansMono"

Password Reset by Email

LimboAuth integrates with SMTP through JavaMail. Without enabling this feature, players cannot use the /forgotpassword command.

yaml
email:
  enable-email: true
  smtp-host: "smtp.gmail.com"
  smtp-port: 587
  smtp-username: "noreply@keydal.tr"
  smtp-password: "app-specific-password"
  smtp-ssl: false
  smtp-starttls: true

  from-name: "KEYDAL Minecraft"
  from-email: "noreply@keydal.tr"

  subject: "Password Reset Code"
  text: "Hello {USER}, your code is: {CODE}"

  # Code validity period (minutes)
  code-expire-time: 15

Session Management

The session system is used to let a player coming from the same IP back in within a certain period without asking them to log in again.

yaml
session:
  # Session enabled
  remember-session: true

  # Session lifetime (seconds, 3600 = 1 hour)
  session-duration: 86400

  # Should the session be dropped if the IP changes?
  kick-on-ip-change: true

  # Where will the session data be stored?
  # memory (wiped on restart) or database (persistent)
  session-storage: "database"

LimboAuth Commands and Permissions

The player-side and admin-side commands are controlled by separate permissions. Granting them per group with LuckPerms is the healthiest approach.

Player Commands

Creates a new account. Requested when there is no record in the database.

/register SuperSecret123 SuperSecret123

Logs in with an existing account.

/login SuperSecret123

Changes the password. Works after the player has logged in.

/changepassword Old123 New456

Receives a code by email and resets the password (the email module must be active).

/forgotpassword player@example.com

Turns TOTP on/off, gets recovery codes.

/2fa

Admin Commands and Permissions

  • /limboauth reloadlimboauth.admin.reload
  • /limboauth forcechangepassword [player] [new]limboauth.admin.forcechangepassword
  • /limboauth unregister [player]limboauth.admin.unregister
  • /limboauth premium [player] — marks the player as premium, no password is requested
  • /limboauth forceregister [player] [password] — creates a registration while the player is offline

Using It Together with LimboFilter

LimboFilter is a bot filter that kicks in before LimboAuth. When a player sends a handshake they land in LimboFilter first, are checked at the protocol level (chat filter, CPS check, position check), and are then handed over to LimboAuth.

yaml
# plugins/limbofilter/config.yml
filter:
  # When should the filter kick in?
  # ALWAYS (all the time), ON_ATTACK (when an attack is detected)
  filter-mode: "ON_ATTACK"

  # Attack threshold (connections per second)
  cps-threshold: 20

  # Rate limit
  max-connections-per-ip: 3
  connection-limit-seconds: 10

  # Captcha is active in limbofilter too
  captcha: true
  chat-filter: true
  position-check: true

Performance and Optimisation

  • JVM flags: use Aikar flags for Velocity. -Xms2G -Xmx2G -XX:+UseG1GC as the baseline; the LimboAPI+LimboAuth load is usually low.
  • Connection pool: on MySQL keep the HikariCP pool size between 10 and 20. Setting it high eats CPU, setting it low makes logins wait.
  • If you are using H2: do not use it in production. There is a corruption risk beyond 10K records and crash recovery is slow.
  • LimboAPI tick rate: lower it to simulation-distance: 4; limbo is an empty world that needs no rendering anyway.
  • Async logging: in Velocity's velocity.toml, announce-forge: false and kick-existing-players: true.
  • Mojang API cache: keep premium-check-cache at 3600 (1 hour) minimum; if Mojang rate limits you during an attack, every login fails.

Common Problems and Their Fixes

Problem 1: The Player Lands in Limbo but Cannot Chat

Velocity's player-info-forwarding-mode setting is wrong. It should be legacy for players arriving from BungeeCord and modern for modern Paper servers. On the backend servers, velocity-support: true in paper-global.yml and the secret must match as well.

Problem 2: The TOTP Code Is Reported Wrong Every Time

The server clock is not synchronised over NTP. TOTP uses 30-second slices; if the server clock drifts 30s+ from the phone, the code looks wrong. Fix it with timedatectl set-ntp true.

Problem 3: MySQL Connection Timeout

Add &autoReconnect=true&tcpKeepAlive=true to connection-parameters. HikariCP's default timeout is 30s; long-idle connections can drop. Keep maxLifetime: 1800000 (30 minutes) below MySQL's wait_timeout value.

Problem 4: The Player Is Shown as 'Premium' but Is Still Asked for a Password

It means force-offline-uuid: true has been set. In that case LimboAuth does not apply the premium bypass. Set it to false and make sure save-premium-accounts: true is active. Check whether you have access to the Mojang API: curl https://api.mojang.com/users/profiles/minecraft/Notch.

Problem 5: An Error During Database Migration

When you move to a new version, LimboAuth tries to migrate the schema automatically. If it fails, a backup is taken under ~/.limboauth-backups/. For a manual migration, apply the SQL scripts from the release notes in order.

Problem 6: Too Many 'Failed to check premium status' Warnings

You have hit the Mojang API rate limit. Mojang's servers accept roughly 600 requests per minute. Increase the cache lifetime (premium-check-cache: 7200) and lower the parallel queue (mojang-rate-limit-max-parallel: 5).

Security Best Practices

  • Raise the BCrypt cost: the default is 10; on modern CPUs 12 is recommended. auth.bcrypt-cost: 12. Every +1 of cost doubles the login time.
  • Make TOTP mandatory for admin accounts: totp-need-passed-for-admins: true + the LuckPerms permission.
  • Config file permissions: chmod 600 plugins/limboauth/config.yml. Nobody besides root or the velocity user should be able to read it.
  • Keep the MySQL connection on localhost: do not expose database TCP port 3306 to the outside. bind-address = 127.0.0.1.
  • TLS is recommended: if the proxy and the DB are on different servers, an SSL/TLS connection is mandatory. useSSL=true&requireSSL=true.
  • Regular backups: take a daily backup with mysqldump; if the account database is lost, every player record goes with it.
  • The proxy secret in Velocity: forwarding.secret should be a random 32-character string; the same secret must match in the backend server's paper-global.yml.

A Real Production Configuration Example

The config.yml below is the template we use at KEYDAL on the production Velocity networks we build. It has been tested under a load of 500+ concurrent players.

yaml
# plugins/limboauth/config.yml — production template
auth:
  min-password-length: 8
  max-password-length: 100
  auth-time: 60
  login-attempts: 3
  ip-limit-registrations: 3

  save-uuid: true
  save-premium-accounts: true
  force-offline-uuid: false
  check-password-strength: true

  enable-totp: true
  totp-issuer: "KEYDAL Network"
  totp-need-passed-for-admins: true
  totp-recovery-codes-amount: 16

  premium-check-cache: 7200
  mojang-rate-limit-behavior: "ASSUME_CRACKED"
  mojang-rate-limit-max-parallel: 10

  bcrypt-cost: 12

database:
  storage-type: "mysql"
  hostname: "127.0.0.1:3306"
  user: "limboauth"
  password: "${LIMBOAUTH_DB_PASS}"
  database: "limboauth"
  connection-parameters: "?autoReconnect=true&tcpKeepAlive=true&useSSL=false&serverTimezone=UTC&characterEncoding=utf8"

  hikari:
    maximum-pool-size: 15
    minimum-idle: 5
    connection-timeout: 10000
    idle-timeout: 600000
    max-lifetime: 1700000

captcha:
  need-captcha: true
  ip-captcha-limit: 15
  captcha-duration: 30
  regen-on-wrong: true
  captcha-length: 5

session:
  remember-session: true
  session-duration: 86400
  kick-on-ip-change: false
  session-storage: "database"

email:
  enable-email: true
  smtp-host: "smtp.sendgrid.net"
  smtp-port: 587
  smtp-starttls: true
  from-name: "KEYDAL Minecraft"
  from-email: "noreply@keydal.tr"
  code-expire-time: 15

Migrating from AuthMe to LimboAuth

If you have an existing AuthMe ReReloaded installation, migrating to LimboAuth is possible. Because the password hashes (BCrypt) are compatible, users do not have to re-enter their passwords. The steps:

  • 1. Back up AuthMe's authme MySQL table: mysqldump authme authme_users > authme.sql
  • 2. Install LimboAuth and let it create the schema (first run).
  • 3. Run the migration SQL:
  • INSERT INTO limboauth_auth (lower_nickname, nickname, hash, ip, premium_uuid, reg_date, login_date) SELECT LOWER(username), realname, password, ip, NULL, regdate, lastlogin FROM authme_users;
  • 4. Verify the hash type in LimboAuth: AuthMe's 'BCRYPT' hashes carry over directly, 'SHA256' needs an extra step.
  • 5. Remove the AuthMe plugin and restart Velocity.

Frequently Asked Questions

Is LimboAuth free?

Yes, it is fully open source (MIT licence) and free. There is no restriction on commercial use.

Is there 1.8 client support?

Together with LimboAPI it supports every Minecraft protocol from 1.7.x through 1.21.x. There is no need to install ViaVersion / ViaBackwards (it is built into LimboAPI).

Do Bedrock (Floodgate) players have to authenticate too?

Bedrock players arriving through Floodgate are already considered authenticated by Microsoft. With auth.floodgate-need-auth: false you can exempt Bedrock players from auth.

Can the database be on another server?

Yes, remote MySQL/PostgreSQL is supported. But latency matters a great deal — under heavy login load, 5 ms+ of RTT between the proxy and the DB affects TPS. Keep the DB in the same DC as the proxy and use TLS.

Is it enough against a bot attack?

On its own LimboAuth provides basic protection. For serious DDoS/bot attacks, LimboFilter + Cloudflare Spectrum (TCP proxy) or KEYDAL's DDoS-protected VPS plans are recommended.

Is it compatible with GeyserMC?

Yes, fully compatible. A Geyser + Floodgate setup works with LimboAuth without issues. For Bedrock players bedrock.require-register: false is recommended (Microsoft auth is already there).

Resources and Official Documentation

The LimboAuth, LimboAPI and LimboFilter projects are actively developed by the Elytrium team. First-hand sources for the current version, bug reports and detailed API documentation: