Secure, modern authentication for offline-mode Minecraft servers. Supports Paper, Purpur, Spigot, Velocity, BungeeCord and more.
Industry-standard bcrypt hashing. Passwords are never stored in plain text.
Players who reconnect from the same IP are automatically authenticated. Expiry is fully configurable.
Mojang-verified players skip login automatically when premium mode is enabled.
Bedrock players via Geyser + Floodgate are auto-authenticated without a password.
Optional two-factor authentication using any standard authenticator app.
Account lockout and IP banning after too many failed login attempts.
Blocks IPs that join too many times in a short window to prevent bot attacks.
Optionally block VPN and proxy connections using proxycheck.io.
Every message, title, color and timing is configurable. Supports hex colors and gradients.
SQLite for single servers, MySQL for shared data across a full network.
Full Velocity and BungeeCord proxy support with NanoLimbo integration.
Track active sessions, view alt accounts, and manage IP bans from one command.
Download PSGLogin-paper.jar and place it in your /plugins/ folder. Start the server once to generate config files, then stop it.
Open plugins/PSGLogin/config.yml and set your preferences:
# Make sure proxy is disabled for standalone proxy: enabled: false main: auth-time: 60 # seconds to login before kick min-password-length: 6 max-password-length: 32 auto-login: enabled: true expiry-seconds: 86400 # 24h, set 0 for unlimited bedrock: auto-login: true # Floodgate players skip login database: type: SQLITE # or MYSQL
Edit plugins/PSGLogin/messages.yml to change any title, chat message, color or timing. Supports &a legacy codes and &#FF5733 hex colors.
Start your server, log in as admin and run /psglogin setspawn where you want players to land after login.
Download and run NanoLimbo on port 65535 (or any free port). It needs no extra configuration — it is just a blank void world.
[servers] limbo = "127.0.0.1:65535" lobby = "127.0.0.1:25577" try = [ "limbo" # unauthenticated players land here ]
Drop PSGLogin-velocity.jar into Velocity's /plugins/ folder. Start once to generate config, then stop.
limbo-server: limbo # must match velocity.toml main-server: lobby # must match velocity.toml auth-time: 60 premium: enabled: true bedrock: auto-login: true auto-login: enabled: true expiry-seconds: 86400 # Generate any random 64-character string access-token: "YOUR_SECRET_TOKEN_HERE" database: type: MYSQL # recommended for networks
Drop PSGLogin-paper.jar into each Paper server's /plugins/ folder. Start once to generate config, then stop.
proxy: enabled: true access-token: "YOUR_SECRET_TOKEN_HERE" # Must match exactly what you set in velocity-config.yml database: type: MYSQL mysql: host: your-db-host database: psglogin # same DB as Velocity username: youruser password: yourpassword
Drop PSGLogin-bungee.jar into BungeeCord's /plugins/ folder. Start once to generate config, then stop.
limbo-server: limbo main-server: lobby auth-time: 60 access-token: "YOUR_SECRET_TOKEN_HERE"
servers: limbo: address: localhost:65535 restricted: false lobby: address: localhost:25577 restricted: false listeners: - priorities: - limbo
Same as Velocity — set proxy.enabled: true and the matching access-token in each Paper server's config.yml.
| /register <pass> <pass> | Create a new account |
| /login <password> | Login to your account |
| /logout | Log out and return to limbo |
| /changepassword <old> <new> | Change your password |
| /unregister <password> | Delete your account |
| /2fa enable | Enable two-factor authentication |
| /2fa disable <code> | Disable two-factor authentication |
| /psglogin reload | Reload all config files |
| /psglogin status <player> | View player auth status |
| /psglogin sessions | View active session count |
| /psglogin unregister <player> | Force unregister a player |
| /psglogin forcepassword <p> <pass> | Force change a password |
| /psglogin tempbanip <player> | Temporarily ban player's IP |
| /psglogin unbanip <ip> | Unban an IP address |
| /psglogin listbans | List all banned IPs |
| /psglogin resetattempts <player> | Reset failed login attempts |
| /psglogin ipinfo <ip> | Show accounts from an IP |
| /psglogin alts <player> | Show alt accounts |
| /psglogin setspawn | Set the post-login spawn |
| /psglogin antibot <on|off> | Toggle anti-bot protection |
# Format: &#RRGGBB "&#FF4500&lPSGLogin" "�E676Welcome back!" "&#FFD700Gold text"
login-success: | &f &8[&a&l»&8] &7Welcome back, &a%player%&7! &f register-success: | &f &8[&a&l»&8] &7Hi &a%player%&7! Useful commands: &f &a&l» &7/changepassword <old> <new> &f &a&l» &7/logout &f
| %player% | Player's username |
| %time% | Time remaining (seconds) |
| %attempts_left% | Login attempts left |
| %min% | Min password length |
| %max% | Max password length |
| %token% | 2FA secret token |
| %codes% | 2FA recovery codes |
| %ip% | Player IP address |
# ── PROXY MODE ── set false for standalone Paper proxy: enabled: false # ── AUTH TIME ── seconds player has to login before kick # Set 0 to disable the time limit entirely main: auth-time: 60 min-password-length: 6 max-password-length: 32 register-confirm-password: true # /register <p> <p> or /register <p> ip-limit-registrations: 3 # max accounts per IP # ── AUTO LOGIN ── same IP reconnect skips login auto-login: enabled: true expiry-seconds: 86400 # 86400=24h 43200=12h 0=unlimited # ── PREMIUM ── Mojang accounts skip login (online-mode only) premium: enabled: false # set true only if server is in online-mode # ── BEDROCK ── Floodgate/Geyser players skip login bedrock: auto-login: true # ── SECURITY ── security: brute-force: max-attempts: 5 # failed logins before account lock lock-duration: 300 # seconds account stays locked ip-max-attempts: 10 # failed logins before IP ban ip-ban-duration: 600 # seconds IP stays banned anti-bot: enabled: true max-joins-per-ip: 3 # max joins from one IP per window time-window: 10 # seconds for the window
# Change the plugin prefix shown in chat prefix: "&8[&cPSGLogin&8]&r " # Title shown after successful login (%player% = player name) titles: success: title: "&a&lHi %player%" subtitle: "&aLogged in" fadeIn: 30 # ticks (20 ticks = 1 second) stay: 100 fadeOut: 30 # Multiline chat message after login messages: login-success: | &f &8[&a&l»&8] &7Welcome back, &a%player%&7! &f register-success: | &f &8[&a&l»&8] &7Welcome, &a%player%&7! Here are your commands: &f &a&l» &7/changepassword &f &a&l» &7/logout &f
/psglogin setspawn # sets spawn where you're standing /psglogin setloginarea # sets a separate login area (optional)
java -jar NanoLimbo.jar — it generates a config.[servers] # Name on the left must match limbo-server in velocity-config.yml limbo = "127.0.0.1:65535" # NanoLimbo port lobby = "127.0.0.1:25577" # Paper lobby port pvp = "127.0.0.1:25578" # other Paper servers (optional) # Players are sent here first when they connect try = [ "limbo" ] # Must be false for offline-mode authentication to work online-mode = false
# ── SERVERS ── must match names in velocity.toml [servers] limbo-server: limbo main-server: lobby # ── AUTH TIME ── seconds before unauthenticated player is kicked # Set 0 to disable auth-time: 60 # ── DELAY ── ms to wait before sending AUTH to Paper after login # Increase if players arrive on Paper before receiving the AUTH message post-auth-message-delay: 1000 # ── PREMIUM ── Mojang accounts auto-login (Velocity online-mode) premium: enabled: true # ── BEDROCK ── Floodgate players auto-login bedrock: auto-login: true # ── AUTO LOGIN ── reconnect from same IP skips login auto-login: enabled: true expiry-seconds: 86400 # 0 = never expires # ── ACCESS TOKEN ── must match every Paper server's config.yml # Generate any random 64-character string and paste it here access-token: "CHANGE_ME_TO_A_RANDOM_64_CHAR_STRING" # ── DATABASE ── SQLite for single server, MySQL for networks database: type: MYSQL mysql: host: localhost port: 3306 database: psglogin username: root password: yourpassword
# Prefix shown in all chat messages prefix: "&8[&#FF4500&lPSGLogin&8]&r " # Title shown while player needs to register titles: register: title: "&#FF4500&lREGISTER" subtitle: "&#FFD700Use /register <password> <password>" interval: 4 # repeat every 4 seconds login: title: "&#FF4500&lLOGIN REQUIRED" subtitle: "&#FFD700Use /login <password>" interval: 4 success: title: "�E676&lHi %player%" subtitle: "EF0AE&oLogged in" # Chat message shown after login (multiline supported) messages: login-success: | &f &8[&a&l»&8] &7Welcome back, &a%player%&7! &f register-success: | &f &8[&a&l»&8] &7Welcome, &a%player%&7! &f &a&l» &7/changepassword &a&l» &7/logout &f
# ── PROXY MODE ── MUST be true for Velocity setup proxy: enabled: true # Must match access-token in velocity-config.yml EXACTLY access-token: "CHANGE_ME_TO_A_RANDOM_64_CHAR_STRING" # ── DATABASE ── use same MySQL DB as Velocity for shared data database: type: MYSQL mysql: host: localhost port: 3306 database: psglogin # same database name as Velocity username: root password: yourpassword
Must be online before Velocity tries to connect to it.
Lobby, survival, pvp — all Paper servers must be up before Velocity.
Velocity connects to all backends on startup. Players can now join.
database: type: SQLITE
database: type: MYSQL mysql: host: localhost # your database server IP port: 3306 # default MySQL port database: psglogin # database name (create it first) username: root password: yourpassword pool-size: 10
-join ((48..57+65..90+97..122) | Get-Random -Count 64 | % {[char]$_})openssl rand -hex 32access-token in both velocity-config.yml and every Paper server's config.yml. They must match exactly.
velocity.toml [servers] must exactly match limbo-server in velocity-config.yml.proxy.enabled: true is set in Paper's config.yml and the access-token matches exactly between Velocity and Paper.bedrock.auto-login: true and Bedrock players are automatically authenticated without needing a password./2fa enable, scan the QR code URL in an authenticator app (Google Authenticator, Authy, etc.), then use /login <password> <code> to login with 2FA.