Player Authentication (Login/Register)
Relevant source files
The following files were used as context for generating this wiki page:
- Plugin/src/main/java/xyz/xreatlabs/nexauth/common/authorization/AuthenticAuthorizationProvider.java
- Plugin/src/main/java/xyz/xreatlabs/nexauth/common/command/commands/authorization/RegisterCommand.java
- Plugin/src/main/java/xyz/xreatlabs/nexauth/common/command/commands/authorization/LoginCommand.java
- Plugin/src/main/java/xyz/xreatlabs/nexauth/common/listener/LoginTryListener.java
- Plugin/src/main/java/xyz/xreatlabs/nexauth/common/listener/AuthenticListeners.java
- Plugin/src/main/java/xyz/xreatlabs/nexauth/common/config/ConfigurationKeys.java
- Plugin/src/main/java/xyz/xreatlabs/nexauth/common/database/AuthenticUser.java
The Player Authentication system is a core feature of NexAuth, designed to secure servers running in offline mode by requiring players to register and log in with a password. It manages the entire lifecycle of a player's authentication state, from their initial connection to successful authorization. The system handles manual login/registration via commands, automatic login for premium players and returning players with active sessions, and security measures like login attempt tracking.
Players who are not yet authenticated are placed in a "limbo" state with restricted permissions and are periodically prompted to log in or register. Once authenticated, they are moved to a designated lobby server and their full permissions are restored. This system is primarily managed by the AuthenticAuthorizationProvider, various command handlers, and event listeners that react to player connection events.
Core Components
The authentication system is composed of several key classes that work together to manage player state and handle authentication logic.
| Class | Description | Source File |
|---|---|---|
AuthenticAuthorizationProvider | Manages the authorization state of all players. Tracks who is unauthenticated, handles authorization success, and sends periodic reminders. | AuthenticAuthorizationProvider.java |
AuthenticListeners | Listens for player connection events (onPreLogin, onPostLogin) to initiate the authentication process and decide if a player needs to log in manually. | AuthenticListeners.java |
LoginCommand | Handles the /login command, verifying the player's password and 2FA code. | LoginCommand.java |
RegisterCommand | Handles the /register command, validating and hashing the new password and creating the player's account. | RegisterCommand.java |
LoginTryListener | Tracks failed login attempts for each player to prevent brute-force attacks. | LoginTryListener.java |
AuthenticUser | Data model representing a player's account details, including hashed password, UUIDs, and session information. | AuthenticUser.java |
The following diagram illustrates the relationships between these core components.
Authentication Lifecycle
The authentication process begins the moment a player attempts to connect to the server. The system evaluates whether the player can be logged in automatically or if they must authenticate manually.
Player Connection and Initial Check
This sequence diagram shows the high-level flow from a player joining to being either authorized or placed in a waiting state.
Authorization State Management
When a player requires manual authentication, the AuthenticAuthorizationProvider begins tracking them.
- The player's instance is added to the
unAuthorizedmap. - The system sends periodic notifications to the player, prompting them to act. These can be chat messages, titles, and action bars, depending on the configuration.
- If the player fails to authenticate within the time limit defined by
seconds-to-authorize, they are kicked. - Once the player successfully uses
/loginor/register, they are removed from theunAuthorizedmap, and theauthorize()method is called to complete the process.
Sources: AuthenticAuthorizationProvider.java:60-62, 113-132, 149-178
Manual Authentication Commands
Players use /register and /login to manage their accounts.
Registration (/register)
The /register command allows a new player to create an account.
Key validations during registration include:
- Ensuring the player is not already registered.
- Checking if the two provided passwords match.
- Validating the password against length requirements (
minimum-password-length) and a list of forbidden passwords.
Sources: RegisterCommand.java:44-50, AuthenticNexAuth.java:191-201, ConfigurationKeys.java:302-307
Login (/login)
The /login command allows a registered player to authenticate their session.
Login Attempt Throttling
To prevent brute-force attacks, the LoginTryListener tracks failed login attempts.
- A failed attempt is recorded when a
LoginTryEventis fired from theLoginCommand. - The number of attempts is stored in a Caffeine cache that expires after a configured duration (
milliseconds-to-refresh-login-attempts). - If a player exceeds
max-login-attempts, they are kicked from the server.
Sources: LoginTryListener.java:30-51, ConfigurationKeys.java:110-120
Automatic Login
NexAuth supports two methods for automatic login to improve user experience.
Session-Based Login
If a player rejoins the server from the same IP address within a configured time frame, they can be logged in automatically.
- Condition:
user.getLastAuthentication()is within thesession-timeoutduration and the current IP matches the stored IP. - Action: The player is authenticated with the reason
SESSION. - This feature is disabled if
session-timeoutis set to 0 or less.
Sources: AuthenticListeners.java:58-61, ConfigurationKeys.java:314-319
Premium Auto-Login
Players with a premium (paid) Mojang account can be automatically logged in without needing a password.
- Condition: The
Userobject has a non-nullpremiumUUID. This is typically set during the pre-login phase or via the/premiumcommand. - Action: The player is authenticated with the reason
PREMIUM. - A title is shown to the player if
use-titlesis enabled.
Sources: AuthenticListeners.java:51-57, AuthenticUser.java:101-103, ConfigurationKeys.java:122-127
The logic for choosing the login path is handled in AuthenticListeners.
Sources: AuthenticListeners.java:50-63
User Data Model
Player authentication data is stored in the AuthenticUser object, which is then persisted to the configured database.
| Field | Type | Description |
|---|---|---|
uuid | UUID | The player's offline-mode UUID. |
premiumUUID | UUID | The player's premium Mojang UUID, if linked. Enables auto-login. |
hashedPassword | HashedPassword | The player's hashed password. Null if not registered. |
lastNickname | String | The last known in-game name of the player. |
joinDate | Timestamp | The date the player first joined. |
lastSeen | Timestamp | The timestamp of the player's last connection. |
secret | String | The secret key for 2FA, if enabled. |
ip | String | The last known IP address of the player. |
lastAuthentication | Timestamp | The timestamp of the last successful authentication, used for sessions. |
lastServer | String | The last server the player was on. |
email | String | The player's registered email for password recovery. |
| Sources: AuthenticUser.java:16-37 |
Relevant Configuration
The following configuration keys in config.yml directly control the behavior of the login and registration system.
| Key | Default Value | Description |
|---|---|---|
allowed-commands-while-unauthorized | ["login", "register", ...] | List of commands a player can use before being authenticated. |
default-crypto-provider | BCrypt-2A | The hashing algorithm used for new passwords. |
max-login-attempts | -1 | Number of incorrect password attempts before kicking the player. -1 disables it. |
milliseconds-to-refresh-login-attempts | 10000 | Time in milliseconds before a player's failed login attempts are reset. |
seconds-to-authorize | -1 | Time limit in seconds for a player to log in or register. -1 disables it. |
minimum-password-length | -1 | The minimum required length for a password. -1 disables it. |
session-timeout | 0L | Time in seconds for a session to be valid for auto-login. 0 or less disables it. |
auto-register | false | If true, automatically registers players who have a premium username. |
use-titles | true | Whether to show titles (e.g., "Login", "Register") to unauthenticated players. |
use-action-bar | false | Whether to show action bars to unauthenticated players. |
milliseconds-to-refresh-notification | 10000 | How often to send login/register prompts to unauthenticated players. |
| Sources: ConfigurationKeys.java |