authlib-injector: running your own Yggdrasil authentication for Minecraft
Build your own Minecraft authentication system.
At a glance
- What is it?
- authlib-injector is a Java agent that patches Mojang's authlib at runtime so a Minecraft client can log in against a server you control, and it ships the specification that such a server has to implement. The interesting parts are the Mojang namespace trick, the built-in HTTP server that some features depend on, and the AGPL exception that lets you load the agent without the licence reaching your own code.
- Who is it for?
- authlib-injector suits anyone running a Minecraft server that wants real account authentication, Mojang skins, profile keys or a username policy instead of offline mode, and it is a poor fit for a server that is content with offline mode and the two seconds it takes to start.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 21 days ago.
- What is it written in?
- Mainly Java, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A Java agent that rewrites authlib while the game runs
authlib-injector exists to solve one problem: Minecraft clients normally authenticate against Mojang's own Yggdrasil servers, and there is no supported way to point them at a different one. The project does it by modifying the authlib library at runtime, inside the client JVM, so the client ends up talking to a verification server you control. The README describes it in one line as implementing off-game login by modifying authlib at runtime, and as providing a specification for Yggdrasil server implementations.
That second half matters as much as the code. A runtime patch only works if the server on the other end speaks the protocol the patched client expects, so the project also documents the API that such a server has to implement. The project pages at authlib-injector.yushi.moe and the wiki linked from the README are the reference for that side.
The mechanism is a Java agent, and that single word explains most of the design. A Java agent is loaded into a virtual machine by a startup argument, and it gets a hook into class loading. The injector's debug options name the hook directly: one option dumps the classes it modified, and another prints classes it analysed but did not change. The package list option exists for the same reason, letting an operator exclude packages from analysis entirely so that a class the injector would otherwise rewrite is left alone.
That the whole thing is a JVM-level intervention rather than a launcher patch is what allows it to work with the official client. There is no custom launcher, no modified game file, and no separate download that a player has to trust.
The audience is server operators who want authentication to mean something: a real account system, a username policy, or the Mojang skin and profile key features that the official client expects to be available.
Building with Gradle and pointing at the jar with one argument
The build is short. The README lists the build dependencies as Gradle and JDK 17 or newer, with a target Java version of 8 for the output. The target of 8 with a JDK 17 toolchain is a deliberate combination: the agent has to load into whatever Java the player happens to be running the game on, and the client has historically shipped with an older runtime than a modern developer machine.
The documented build command is a single word:
gradleand the README states that the build output lands under build/libs. The repository also ships a Gradle wrapper, with gradlew and gradlew.bat at the root next to build.gradle and settings.gradle, so a checkout can be built without a system wide Gradle installation.
Deployment is one JVM argument. The README shows it as a javaagent argument that pairs the path to authlib-injector.jar with the verification server URL, which is the API address of the server, joined by an equals sign. Nothing else has to change in the launcher or the server configuration, and the same argument works on the client and on the server side, because the injector patches whichever side needs the other behaviour.
Two practical consequences follow from the argument being on the command line. First, the path has to be valid for every machine that runs the client, so most deployments ship the jar with the game and reference a relative or well known path. Second, the verification server URL is baked into the launch command, so changing authentication servers means changing how the client is started, which for a player facing setup means updating whatever launches the game.
For distribution, the README points to a download mirror run by BMCLAPI, and suggests supporting BMCLAPI as the way to support the project's development.
The Mojang namespace and the version 12 UUID
The Mojang namespace is the feature that makes this injector interesting, and the mechanism behind it is a piece of identifier engineering.
When enabled, a player can use a virtual character named with the username followed by an @mojang suffix, and that virtual character resolves to the real Mojang account's skin. The README gives the in-game forms: a skull command with a SkullOwner value of Notch@mojang, and an NPC skin command pointing at the same name. The displayed skin is Notch's.
The virtual character has its own UUID, and it is deliberately different from the real one. The injector sets the highest bit of the time_hi_and_version field, which RFC 4122 section 4.1.3 describes, and the README shows the two identifiers side by side:
069a79f4-44e9-4726-a5be-fca90e38aaf5 Notch
069a79f4-44e9-c726-a5be-fca90e38aaf5 Notch@mojangThe reasoning is laid out too. RFC 4122 defines six possible version values, 0 through 5, and the version is stored with its highest bit always zero. Mojang uses version 4, the random variant, so a UUID with the top bit flipped has version 12, a value no standard UUID can have. That makes the virtual identifiers permanently distinguishable from any real Mojang UUID, which is what stops a virtual character from ever being confused with an official one.
Whether the feature is on is decided by two inputs that have to agree. The client side flag can be default, enabled or disabled, and the default behaviour depends on whether the verification server has set the feature.no_mojang_namespace option. So the server is the authority, and the local flag can override it. That pattern repeats for most of the optional features, and it is worth understanding before anything is deployed.
The built-in HTTP server that two features depend on
The injector runs its own HTTP server inside the client, and that is a dependency worth planning for rather than discovering later.
The port is set with the httpdPort option, and the README states the default is 0, which means a random port is assigned. A fixed port is what you want if something outside the game has to reach that server, and a random one is what you want if you would rather not have a predictable listener. The server can be turned off entirely with disableHttpd, and the README is explicit about what that costs: the Mojang namespace and the legacy skin API polyfill both stop working, because they are the features that depend on it.
The legacy skin polyfill is the older of the two. It serves the pre-existing skin endpoint, the GET request to /skins/MinecraftSkins/{username}.png path, which older clients and third party tools still expect. Whether it is enabled by default depends again on the server, in this case on the feature.legacy_skin_api option.
There is a third, quieter use of the same machinery. By default the injector shows the verification server name on the Minecraft main menu, and it does so by changing the version type argument the client passes. The noShowServerName option disables that, which matters for operators who do not want their authentication setup advertised to every player in the server list.
The proxy option belongs here too. The mojangProxy setting routes access to the Mojang authentication service through a SOCKS proxy, given in the socks://host:port form, and the README stresses that it applies only to the Mojang namespace feature, because that is the only path that talks to Mojang servers. Proxying traffic to a custom verification server is a different matter, and the README points at the Java proxy documentation for that.
Anti-features, profile keys and username checks, all decided server side
Several of the injector's options are really requests to the authentication server, and the local flag only expresses a default.
The mojangAntiFeatures option controls a group of Minecraft anti-features. The README lists them: the server blocklist, and an interface for querying user permissions, which covers chat permission, multiplayer permission, telemetry, and offensive content filtering. The listed defaults are permissive in the sensible direction, with chat and multiplayer permissions allowed and telemetry and content filtering off when the feature is disabled. The default value depends on whether the server has set feature.enable_mojang_anti_features, and the README says the default is disabled.
The profileKey option is about message signing. That feature was introduced in 22w17a, and when it is enabled Minecraft sends a POST request to /minecraftservices/player/certificates to obtain a key pair issued by the verification server, which is then used to sign chat messages in multiplayer. The README notes that it needs server support, and that it is disabled by default unless the server sets feature.enable_profile_key.
The usernameCheck option is the one with a visible side effect. When it is disabled, the injector turns off the username checks of Minecraft, BungeeCord and Paper, and the README warns that enabling it means players whose names contain characters outside English cannot join the server. The default is disabled unless the server sets feature.usernameCheck.
The pattern across all three is the same. The verification server advertises which features it supports, and the injector uses its own default value only when the server has said nothing. That is the right design for a client side tool, since it keeps the authoritative decision on the side that also owns the user database.
Logging quirks, debug switches and the log file that gets overwritten
The logging behaviour has one surprise worth reading twice. By default the injector writes to the console and to an authlib-injector.log file in the current directory. The noLogFile option turns the file off, leaving console output only. The README also points out that the injector's logs do not go into the Minecraft server or client log file, so an operator looking in the usual place will find nothing.
The second surprise is concurrency. The log file is cleared on every start, and if several processes use the same log file, only the earliest one to start will succeed in opening it. On a shared hosting setup where several Minecraft processes run from the same working directory, that means one process gets the file and the others get console output only, silently.
The debug options are the tool for understanding what the agent actually did. The debug flag can be given on its own, which is equivalent to a verbose, authlib combination, or with a comma separated list of options: verbose for detailed logs, authlib to turn on Mojang authlib debug output, dumpClass to dump the classes it modified, and printUntransformed to print classes it analysed but did not change, which implies verbose.
That last option is the useful one for a failed deployment. If a class was analysed and then left alone, the reason it was not transformed is usually a missing feature flag on the server or a package excluded by the ignoredPackages option.
The mojangNamespace, legacySkinPolyfill, mojangAntiFeatures, profileKey and usernameCheck options all take the same three value form, default, enabled or disabled, which keeps a launch script readable when a deployment needs to override several of them at once.
The AGPL exception is what makes the agent usable
The licence situation is the part of this project most likely to surprise a server owner, because the repository carries a custom licence that the metadata field cannot classify and the README describes precisely.
The wiki subdirectory is licensed under CC BY-SA 4.0, so the documentation can be reused and adapted. Everything else is under the GNU Affero General Public License v3.0 or later, with an added AUTHLIB-INJECTOR exception, and the full text including that exception is in AGPLv3-with-authlib-injector-exception.txt at the repository root. The repository also carries a COPYING.md and a badge that labels the project AGPL-3.0.
The exception has three cases, and the README lists them. If your program includes the unmodified binary of this work as a package without statically or dynamically linking to it, that behaviour does not bring your work under the AGPL. If your program interacts with the work through the inter-process communication interfaces it provides, such as the HTTP API, the same applies. If your program loads the work as a Java agent into a Java virtual machine, the same applies again.
The third case is the one that matters for almost every real deployment, because that is exactly how the injector is used. Without it, a server that ships the agent would be arguable copyleft, and the exception removes that argument for the ordinary case.
This is a licensing observation, not legal advice, and it does not replace reading the exception text for your own distribution model. The important thing is that the exception is written down rather than implied, and that the exact file to read is named in the repository root.
The rest of the repository is set up for contributors: a CONTRIBUTING.md, a bilingual README with a Simplified Chinese version and an English one, and a wiki directory that carries its own licence.
Offline mode against a real authentication server
The alternative to this project is not a competing injector. It is to run the server in offline mode, and the difference in approach is the whole design of the injector.
In offline mode the server accepts any username, verifies nothing, and needs no verification service, no token exchange and no agent on the client. Installation is a server setting rather than a client side operation, so nothing is installed on players' machines and there is no jar to distribute, no JVM argument to manage, and no proxy in the way if a player cannot reach the authentication server.
What you give up is everything the injector exists to make possible. With a real authentication server, accounts exist on the server, so a ban applies to an account rather than to a name someone types, and the username policy can be enforced, which is the point of the usernameCheck option. You get the Mojang namespace, so a player can present a real Mojang skin on a server that does not own the game. You get profile keys, so chat messages can be signed. You get the legacy skin endpoint for tools that still call it, and the server name in the client window.
The two approaches are also different in where the risk lives. Offline mode has no moving parts and no attack surface beyond the game itself, but it also has no audit trail. A verification server holds credentials and issues tokens, which is a system that has to be maintained, secured, and kept compatible with client versions.
The choice is a product decision rather than a technical one. Offline mode is right for a small server that just needs names. A verification server is right when identity, enforcement or the official client features matter, and authlib-injector is the tool that makes the second option work with an unmodified client.
Release cadence, the develop branch and a Nix flake
The repository is not archived and the last push was on 2026-10-02. The release history shows v1.2.8 on 2026-07-11, v1.2.7 on 2025-12-16 and v1.2.6 on 2025-10-06, so the published line moves a few times a year rather than on a fixed schedule.
The default branch is develop, not main, and the CI badge in the README points at the ci workflow on that branch. That is worth knowing before you pin a version, because a checkout of the default branch is a development state rather than the last release. The project is also bilingual, with README.md in Simplified Chinese and README.en.md in English, and the wiki is published separately at the project's GitHub Pages site.
The build tooling has a second option worth noting. Alongside the Gradle files and the wrapper, the repository carries flake.nix and flake.lock, so a Nix user can enter a development environment with the toolchain already resolved rather than installing Java and Gradle by hand. There is also a build.gradle and settings.gradle at the root, with the source under src/ and the documentation under wiki/.
The upgrade cost for a server operator is mostly in the verification server, not the agent. The client side jar is replaced and the JVM argument stays the same, but each new client version can change what the patched authlib looks like, and the injector's compatibility with that version is the thing to watch. A server that keeps its players on a specific client version has more control here than one that follows the latest client automatically.
Editorial conclusion
authlib-injector suits anyone running a Minecraft server that wants real account authentication, Mojang skins, profile keys or a username policy instead of offline mode, and it is a poor fit for a server that is content with offline mode and the two seconds it takes to start. Verify two things before you deploy it: that your authentication server implements the feature flags the injector consults, since the defaults are decided by the server side, and that you read AGPLv3-with-authlib-injector-exception.txt, because the exception is what keeps the agent from reaching your own code. Build it with Gradle and a JDK 17 or newer, remember the output lands in build/libs, and check the version you ship, since v1.2.8 was published on 2026-07-11 and the working branch is develop.
Frequently asked questions
What does authlib-injector do?
It is a Java agent that modifies Mojang's authlib at runtime so a Minecraft client can log in against a custom verification server instead of Mojang's own. The project also provides the specification for Yggdrasil server implementations.
How do I build authlib-injector?
The README lists Gradle and JDK 17 or newer as the build dependencies, with a target Java version of 8, and gives the build command as gradle. The build output is placed under build/libs, and the repository also ships a Gradle wrapper.
How do I deploy authlib-injector to a Minecraft client?
The README shows a javaagent argument that pairs the path to authlib-injector.jar with the verification server API URL, joined by an equals sign. The jar is then distributed to players, and the argument is added to the Java launch options of the game.
What is the Mojang namespace feature in authlib-injector?
It lets a player use a virtual character named username@mojang that resolves to the real Mojang account's skin, using commands such as a skull with a SkullOwner of Notch@mojang. The virtual character has a distinct UUID whose version field is set to 12 by flipping the top bit, so it can never collide with a real Mojang UUID.
What licence is authlib-injector released under?
The wiki directory is under CC BY-SA 4.0, and all other files are under the AGPLv3 or later with an AUTHLIB-INJECTOR exception, whose full text is in AGPLv3-with-authlib-injector-exception.txt. The exception covers unmodified binary inclusion without linking, interaction through the provided inter-process interfaces such as the HTTP API, and loading the work as a Java agent.
Which authlib-injector options depend on the built-in HTTP server?
The README states that disabling the built-in HTTP server with the disableHttpd option makes the Mojang namespace and the legacy skin API polyfill unavailable. The server's port is set with httpdPort, and it defaults to 0, which means a random port.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/yushijinhun-authlib-injector)Was this useful?