Database Schema
Relevant source files
The following files were used as context for generating this wiki page:- Plugin/src/main/java/xyz/xreatlabs/nexauth/common/database/provider/NexAuthSQLDatabaseProvider.java
- Plugin/src/main/java/xyz/xreatlabs/nexauth/common/database/AuthenticUser.java
- Plugin/src/main/java/xyz/xreatlabs/nexauth/common/database/provider/NexAuthMySQLDatabaseProvider.java
- Plugin/src/main/java/xyz/xreatlabs/nexauth/common/database/provider/NexAuthPostgreSQLDatabaseProvider.java
- Plugin/src/main/java/xyz/xreatlabs/nexauth/common/database/provider/NexAuthSQLiteDatabaseProvider.java
- Plugin/src/main/java/xyz/xreatlabs/nexauth/common/AuthenticNexAuth.java
- Plugin/src/main/java/xyz/xreatlabs/nexauth/common/config/ConfigurationKeys.java
- API/src/main/java/xyz/xreatlabs/nexauth/api/database/WriteDatabaseProvider.java
The NexAuth database system is designed to persistently store all user authentication and profile data. It features a flexible architecture that supports multiple SQL backends, including MySQL, PostgreSQL, and SQLite, chosen via the database.type configuration key. The core of the system is a single table, librepremium_data, which holds all essential information for each user, from credentials to session data.
The system is built on a layered provider model, separating database connection logic from data access operations. This allows for easy extension and maintenance. The schema is also designed to be self-migrating, automatically adding new columns as the plugin is updated, ensuring backward compatibility. For information on migrating from other authentication plugins, see the Database Migration page.
Sources: Plugin/src/main/java/xyz/xreatlabs/nexauth/common/config/ConfigurationKeys.java:218-224, Plugin/src/main/java/xyz/xreatlabs/nexauth/common/database/provider/NexAuthSQLDatabaseProvider.java:302-305, Plugin/src/main/java/xyz/xreatlabs/nexauth/common/AuthenticNexAuth.java:420-444
Architecture
NexAuth employs a provider-based architecture to handle database interactions. This consists of two main components: DatabaseConnector and DatabaseProvider.
DatabaseConnector: Manages the connection pool (using HikariCP) and raw connection details for a specific database type (e.g.,AuthenticMySQLDatabaseConnector).DatabaseProvider: Implements the logic for CRUD (Create, Read, Update, Delete) operations by executing SQL queries via aDatabaseConnector.NexAuthSQLDatabaseProvideris the abstract base class for SQL-based providers.
The main plugin class, AuthenticNexAuth, initializes the appropriate connector and provider based on the database.type setting in the configuration file.
The following diagram illustrates the class hierarchy for the database providers.
Core Table: librepremium_data
All user data is stored in a single table named librepremium_data. This table is created and updated automatically.
Entity Relationship Diagram
This diagram shows the structure of the librepremium_data table.
Column Details
The table is initially created with a base set of columns, and subsequent columns are added if they don't exist during schema validation.
| Column | Type | Constraints | Description |
|---|---|---|---|
uuid | VARCHAR(255) | PRIMARY KEY | The primary identifier for the user. Can be a cracked or premium UUID depending on configuration. |
premium_uuid | VARCHAR(255) | UNIQUE | The user's official Mojang UUID if they are a premium player. Null otherwise. |
hashed_password | VARCHAR(255) | The user's password, hashed by the configured crypto provider. Null if not registered. | |
salt | VARCHAR(255) | The salt used with the password hash. | |
algo | VARCHAR(255) | The identifier of the algorithm used for hashing (e.g., BCrypt-2A). | |
last_nickname | VARCHAR(255) | NOT NULL, UNIQUE | The last known in-game name of the user. |
joined | TIMESTAMP | NULL | The timestamp of the user's first join. |
last_seen | TIMESTAMP | NULL | The timestamp of the user's last session. |
secret | VARCHAR(255) | NULL | The secret key for TOTP-based 2FA. Added automatically if missing. |
ip | VARCHAR(255) | NULL | The last known IP address of the user. Added automatically if missing. |
last_authentication | TIMESTAMP | NULL | The timestamp of the last successful authentication. Used for sessions. Added automatically if missing. |
last_server | VARCHAR(255) | NULL | The name of the last server the player was on. Added automatically if missing. |
email | VARCHAR(255) | NULL | The user's email address for password recovery. Added automatically if missing. |
Sources: Plugin/src/main/java/xyz/xreatlabs/nexauth/common/database/provider/NexAuthSQLDatabaseProvider.java:144-167, 302-329, Plugin/src/main/java/xyz/xreatlabs/nexauth/common/database/AuthenticUser.java
Schema Validation and Evolution
NexAuth automatically manages the database schema through the validateSchema() method. On startup, it checks if the librepremium_data table exists and creates it if not. It then checks for the existence of newer columns and adds them using ALTER TABLE statements, ensuring the schema is always up-to-date without manual intervention.
The following flowchart illustrates the schema validation process:
The initial table creation is performed with this SQL statement:
CREATE TABLE IF NOT EXISTS librepremium_data(
uuid VARCHAR(255) NOT NULL PRIMARY KEY,
premium_uuid VARCHAR(255) UNIQUE,
hashed_password VARCHAR(255),
salt VARCHAR(255),
algo VARCHAR(255),
last_nickname VARCHAR(255) NOT NULL UNIQUE,
joined TIMESTAMP NULL DEFAULT NULL,
last_seen TIMESTAMP NULL DEFAULT NULL,
last_server VARCHAR(255)
)
Database-Specific Implementations
While NexAuthSQLDatabaseProvider defines the common SQL logic, there are specific provider classes for MySQL, PostgreSQL, and SQLite to handle dialect-specific syntax.
| Feature | MySQL - | PostgreSQL - | SQLite - |
| getColumnNames() | SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='librepremium_data' and TABLE_SCHEMA='...' - | SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='librepremium_data' and TABLE_SCHEMA='public' - | PRAGMA table_info(librepremium_data) - |
| getIgnoreSyntax() | IGNORE - | (empty string) - | OR IGNORE - |
| getIgnoreSuffix() | (empty string) - | ON CONFLICT DO NOTHING - | (empty string) - |
| addUnique(column) | CREATE UNIQUE INDEX %s_index ON librepremium_data(%s) - | CREATE UNIQUE INDEX %s_index ON librepremium_data(%s) - | CREATE UNIQUE INDEX %s_index ON librepremium_data(%s); - |
Sources: Plugin/src/main/java/xyz/xreatlabs/nexauth/common/database/provider/NexAuthMySQLDatabaseProvider.java:29-41, Plugin/src/main/java/xyz/xreatlabs/nexauth/common/database/provider/NexAuthPostgreSQLDatabaseProvider.java:27-32, Plugin/src/main/java/xyz/xreatlabs/nexauth/common/database/provider/NexAuthSQLiteDatabaseProvider.java:29-34
Data Access and Retrieval
The NexAuthSQLDatabaseProvider provides a set of methods to interact with the user data. All database operations are designed to be run asynchronously to avoid blocking the main server thread.
Data Retrieval Flow
The following sequence diagram shows the process of fetching a user by their name.
Key Operations
The WriteDatabaseProvider interface defines the standard methods for modifying user data.
| Method | Description |
|---|---|
insertUser(User) | Inserts a single new user into the database. |
insertUsers(Collection<User>) | Inserts a collection of users in a batch, using dialect-specific IGNORE syntax to prevent errors on duplicate entries. |
updateUser(User) | Updates all fields for an existing user, identified by their uuid. |
deleteUser(User) | Deletes a user from the database, identified by their uuid. |
Sources: API/src/main/java/xyz/xreatlabs/nexauth/api/database/WriteDatabaseProvider.java, Plugin/src/main/java/xyz/xreatlabs/nexauth/common/database/provider/NexAuthSQLDatabaseProvider.java:171-260