Skip to content

Authentication

Add minified-auth to your build.gradle file:

repositories {
mavenCentral()
maven { url 'https://jitpack.io' }
}
dependencies {
implementation 'com.github.dervarex.minified:minified-auth:3.0.0'
}

Before using authentication, initialize the AuthManager with a directory where sessions can be stored.

Path authDirectory = Path.of("<auth-directory>");
AuthManager.init(authDirectory);

Before starting a new login, check whether a saved session already exists.

User user = null;
if (AuthManager.hasSessionSaved()) {
user = AuthManager.loginWithSavedSession();
}

If the saved session is valid, loginWithSavedSession() returns the authenticated user.


If no saved session exists, start the Microsoft device code login:

AuthManager.startDeviceCodeLoginAsync();

The login runs asynchronously. You can access its current state using:

LoginState state = AuthManager.getLoginState();

Wait until the user code becomes available:

while (true) {
LoginState state = AuthManager.getLoginState();
if (state.userCode != null && state.verificationUri != null) {
System.out.println(
"Go to " + state.verificationUri
+ " and enter code " + state.userCode
);
break;
}
Thread.sleep(500);
}

The user can then open the verification URL and enter the displayed code.


After displaying the login instructions, wait until authentication succeeds or fails:

while (true) {
LoginState state = AuthManager.getLoginState();
if (state.status == AuthManager.LoginStatus.SUCCESS) {
break;
}
if (state.status == AuthManager.LoginStatus.ERROR) {
throw new IllegalStateException(state.message);
}
Thread.sleep(500);
}

After a successful login, get the authenticated user:

User user = AuthManager.getUser();
System.out.println(
"Logged in as "
+ user.username()
+ " ("
+ user.uuid()
+ ")"
);

Polling getLoginState() in a loop works, but AuthManager also supports pushing state changes directly to a listener - useful if your UI framework already has a callback/observer pattern instead of a poll loop:

LoginStateChangeListener listener = newState -> {
System.out.println("New login state: " + newState.status);
};
AuthManager.addStateChangeListener(listener);

The listener is invoked with the same LoginState snapshot every time AuthManager updates it - during login(), startDeviceCodeLoginAsync(), and resetLoginState(). Remove it once you no longer need updates (e.g. when the login UI closes), the same way you would unsubscribe from any other event in Minified:

AuthManager.removeStateChangeListener(listener);

Path authDirectory = Path.of("<auth-directory>");
AuthManager.init(authDirectory);
User user = null;
if (AuthManager.hasSessionSaved()) {
user = AuthManager.loginWithSavedSession();
}
if (user == null) {
AuthManager.startDeviceCodeLoginAsync();
boolean loginInstructionsShown = false;
while (true) {
LoginState state = AuthManager.getLoginState();
if (!loginInstructionsShown
&& state.userCode != null
&& state.verificationUri != null) {
System.out.println(
"Go to " + state.verificationUri
+ " and enter code " + state.userCode
);
loginInstructionsShown = true;
}
if (state.status == AuthManager.LoginStatus.SUCCESS) {
user = AuthManager.getUser();
break;
}
if (state.status == AuthManager.LoginStatus.ERROR) {
throw new IllegalStateException(state.message);
}
Thread.sleep(500);
}
}
System.out.println(
"Logged in as "
+ user.username()
+ " ("
+ user.uuid()
+ ")"
);

The returned User can now be passed directly to Minified Launch:

Launcher.launchMinecraft(
user,
config
);

Sessions are stored encrypted on disk using a master key. AuthManager.init() accepts an EventBus that these events are dispatched on, see CreateMasterKeyEvent, SaveEncryptedSessionEvent and LoadEncryptedSessionEvent in the Events section for details on exactly when each one fires.