Server-side authentication for Minecraft. Registration, login, IP sessions and a freeze that actually holds. Commands only — players need no client mod.
One codebase covers four targets; the shared logic is written once and the loaders differ only in which events they subscribe to.
| Minecraft | Loader | Artifact | Status |
|---|---|---|---|
| 1.20.1 | Forge | postern-forge-1.20.1-<ver>.jar |
verified on a real server |
| 1.20.1 | NeoForge | postern-neoforge-1.20.1-<ver>.jar |
builds; not verified by running |
| 1.20.1 | Fabric | postern-fabric-1.20.1-<ver>.jar |
builds; not verified by running |
| 1.21.1 | NeoForge | postern-neoforge-1.21.1-<ver>.jar |
builds; not verified by running |
| 1.21.1 | Fabric | postern-fabric-1.21.1-<ver>.jar |
builds; not verified by running |
On 1.20.1 NeoForge is still a fork of Forge from before the two diverged — same
net.minecraftforge.* packages, same mods.toml — so that target reuses the
Forge entry point and buildscript unchanged, differing only in one coordinate.
Classic Forge above 1.20.1 is not built, and not by choice. ModDevGradle's
legacy plugin needs a universal-srg artifact that Forge stopped publishing at
1.20.2, and the only alternative — ForgeGradle 6 — refuses to run on Gradle 9,
which this tree requires for Loom and ModDevGradle. ForgeGradle 7 is unreleased.
Worth revisiting when either changes.
"Verified" here means a real, reobfuscated server was started with the jar and a game client actually joined it. Confirmed that way: the freeze engages (a joined player cannot move or interact), registration issues recovery codes, an IP session lets a returning player back in without a password, and the admin commands answer from the console.
The other four targets have not been started at all. Not yet exercised even on
the verified one: /logout, /changepassword, /recover, the
damage protection, limbo freeze mode, and the lockout after repeated wrong
passwords. They are covered by unit tests, which is not the same thing.
The word is deliberately narrow because everything short of a real client proves less than it looks. 0.1.0 passed a green build, 179 unit tests, a development server and a production server — and still froze nobody, because its mixins were never applied. Only a client joining showed it.
Classic Forge above 1.20.1 is not planned — that ecosystem moved to NeoForge.
- Download the jar for your Minecraft version and loader from the releases page.
- Drop it into the server's
mods/folder. Nothing goes on the client. - Start the server once. Postern writes
config/postern/config.ymlandconfig/postern/lang/, then creates its SQLite database next to them. - Edit the config if you want;
/postern reloadapplies it without a restart.
The server must be in offline mode (online-mode=false) for any of this to make
sense — that is the situation the mod exists for.
If the database cannot be opened, the server refuses to start. That is deliberate: a mod that cannot check a password must not let everyone in.
Players:
| Command | Alias | What it does |
|---|---|---|
/register <password> <repeat> |
/reg |
creates the account, issues recovery codes |
/login <password> |
/l |
logs in |
/logout |
drops the session; the next join asks for the password | |
/changepassword <current> <new> |
changes it and invalidates saved sessions | |
/recover <code> <new password> |
uses one of the recovery codes |
Aliases are configurable.
Administrators (/postern, OP level 2):
/postern reload
/postern user info|register|resetpassword|unregister|unlock|transfer|forcelogin
/postern session list|clear <player|all>
/postern db status|reconnect
reload names the settings it could not apply live instead of silently
ignoring them. transfer warns that a rename leaves world data behind.
The mod exists because of three specific complaints about the alternatives, and each is a design goal rather than a feature bullet.
You cannot configure them. Postern ships a commented config.yml that
explains every option, separate language files with every string, and
/postern reload that applies both without a restart. A typo never stops the
server: bad values are reported in the log and replaced, out-of-range numbers are
clamped.
The freeze leaks. Most mods enumerate what to forbid and eventually miss a packet — EasyAuth has an open issue titled exactly "Fail to freeze player before login". Postern inverts it: a single interception point passes a whitelist of six packet kinds and drops everything else, so a packet added by a future Minecraft version is closed by default rather than open by default.
No admin tools. Reset a password, unlock an account, force a login, inspect sessions, check the database — from in game.
On top of that, Forge is a first-class target on 1.20.1. The strongest existing mod, EasyAuth, supports Fabric, Quilt and NeoForge — but not Forge, where much of the 1.20.1 audience actually is.
Sessions are bound to an IP address, which is all a server-side mod can bind
to. Behind carrier-grade NAT two unrelated people share one address, and everyone
on the host's own machine appears as 127.0.0.1. Postern says so in the config
next to the option and drops sessions on /logout, password change, admin action
and address change.
Capitalisation of a nickname is not cosmetic. On an offline-mode server a
player's identity is derived from the exact name they connect with, so Notch
and notch are different characters with different inventories. Postern finds
the account case-insensitively but refuses the login with an explanation rather
than dropping the player into what looks like a wiped world.
Password hashing never runs on the main thread. At the default cost a single BCrypt verification takes 200–400 ms — four to eight server ticks. Running it inline would be both a lag spike and a free denial-of-service vector.
- No client mod. The password therefore stays in the player's own chat history, reachable with the up arrow. No server-side mod can remove it.
- No premium (licensed account) verification. Everyone uses a password. The cryptographic session check is designed but not implemented, and the config says nothing about it rather than promising it.
- No proxy support. Velocity and BungeeCord are unsupported, and Postern
cannot detect them. Behind a proxy that does not forward player info the
server sees one address for everybody, which would turn IP sessions into
"anyone may enter any account" — switch
session.enabledoff if you run one. - Plugin messages do not reach a frozen player.
custom_payloadis not on the whitelist, because it is the channel mods use for their own handshakes and opening it would let an arbitrary mod act for an unauthenticated player. Mods that require a play-phase handshake with a timeout will not get along with the freeze.
gradlew buildAll
That builds all four targets; the artifacts land in
versions/<version>-<loader>/build/libs/. Plain gradlew build only builds the
currently active Stonecutter node.
Java 17 (1.20.1) and Java 21 (1.21.1) are required, and Gradle downloads whichever is missing — neither has to be installed on the machine.
To run a development server for the active node:
gradlew :1.20.1-forge:runServer
Note that a development server runs on Mojang mappings, so it cannot catch
mapping or mixin-application faults. Those show up only on a real server, and the
build guards against the known one: verifyRefmap fails the build if the Forge
jar has no refmap.
MIT — see LICENSE. The jar bundles third-party libraries, one of them
under LGPL-2.1; THIRD-PARTY.md lists them and the obligations
that come with them, and LICENSE-LGPL-2.1.txt is the
licence itself. All three also travel inside every jar under META-INF/.