Security-first, framework-agnostic PHP 8.2+ user management module for MariaDB/MySQL.
A drop-in auth/user module you can mount into an existing PHP app.
- Not a full framework
- Not a standalone IAM server
- Built for embedding and extension
- Registration + email verification
- Login (username or email) + secure sessions + remember-me
- Password reset + password change
- Role checks (
user,admin,super_admin) with permission checks (can()) - TOTP + recovery codes + step-up verification
- Passkeys (WebAuthn) with safe default disabled mode
- Google OIDC login hooks
- Session/device listing and revocation
- Audit logging for security-sensitive actions
- HTML modules and JSON endpoints
- Install dependencies:
composer install- Configure database (environment mode):
export NEXUS_DB_DSN='mysql:host=127.0.0.1;port=3306;dbname=nexus_user;charset=utf8mb4'
export NEXUS_DB_USER='root'
export NEXUS_DB_PASS=''- Run migrations:
php migrations/run.php- Start demo router:
php -S 127.0.0.1:8080 examples/minimal_router.phpIf you want a cleaner, app-like example (homepage + register/login + restricted user/admin pages), use:
- Configure the demo in this file:
examples/config/module_webapp.config.php
Set at least:
db_dsndb_userdb_password
- Run migrations (uses the same config file by default if
NEXUS_CONFIG_FILEis not set):
php migrations/run.php- Start the demo app:
php -S 127.0.0.1:8081 examples/module_webapp.phpThen open http://127.0.0.1:8081.
Optional: use a different config file via environment variable:
NEXUS_CONFIG_FILE=/absolute/path/to/your.config.php php -S 127.0.0.1:8081 examples/module_webapp.phpThis example demonstrates the intended drop-in style:
- include the module
- instantiate core services once
- protect host-app routes using session + role checks
Use Composer to install this module into your application. This is the recommended approach for production usage.
If the package is available on Packagist:
composer require silverday/nexus-dropin-user:^0.2.1If you want to install directly from GitHub (VCS source):
{
"repositories": [
{
"type": "vcs",
"url": "https://github.com/SilverDay/nexus.git"
}
]
}Then run:
composer require silverday/nexus-dropin-user:^0.2.1Manual unzip/copy into your app directory is possible for experiments, but not recommended because dependency updates, autoloading, and version pinning are harder to maintain.
The module now supports both environment-based and file-based configuration.
Used by default when no config file is provided.
Primary keys:
NEXUS_DB_DSNNEXUS_DB_USERNEXUS_DB_PASSNEXUS_TOTP_KEYNEXUS_GOOGLE_OIDC_CLIENT_IDNEXUS_GOOGLE_OIDC_CLIENT_SECRETNEXUS_GOOGLE_OIDC_REDIRECT_URINEXUS_PASSKEY_WEBAUTHN_ENABLED
The demo router and migration runner look for an app-local config file first:
examples/minimal_router.phpdefaults toexamples/config/module.config.phpmigrations/run.phpdefaults toexamples/config/module.config.php
Override options (in precedence order):
NEXUS_CONFIG_FILE_PATHconstant in your entrypoint- Web-server scoped
$_SERVER['NEXUS_CONFIG_FILE'] - Process environment variable
NEXUS_CONFIG_FILE - App-local default file path
You can still use NEXUS_CONFIG_FILE when useful, but for multi-app servers prefer app-local files or per-app entrypoint constants.
Migration runner also accepts an explicit config path argument:
php migrations/run.php /path/to/your/module.config.phpSee the template in examples/config/module.config.php.
Supported config keys include:
- Core config:
db_dsn,db_user,db_password,from_email,from_name - Security behavior:
secure_cookies,same_site,ip_binding_mode,bind_user_agent - Phase-2 toggles/secrets:
totp_key,google_oidc_*,passkey_webauthn_enabled - Mail transport:
mail_transport,smtp_host,smtp_port,smtp_username,smtp_password,smtp_encryption,smtp_timeout_seconds - Mail template files:
email_template_locale,email_template_roots,verification_link_template,admin_registration_notify_to - Optional mail fallback templates:
email_templates - UI fields:
profile_fields
You can configure both what is sent and how it is sent from the config file.
Transport options:
mail_transport = null(default; no mail sent)mail_transport = php(uses PHPmail())mail_transport = smtp(uses SMTP with optional AUTH/STARTTLS)
Example transport config:
'mail_transport' => 'smtp',
'smtp_host' => 'smtp.example.com',
'smtp_port' => 587,
'smtp_username' => 'smtp-user',
'smtp_password' => 'smtp-password',
'smtp_encryption' => 'tls', // tls|ssl|none
'smtp_timeout_seconds' => 10,
'verification_link_template' => 'https://app.example.com/verify-email?token={{token}}',
'admin_registration_notify_to' => 'security@example.com,ops@example.com',Email text is file-based by default. Template file lookup is:
<root>/<locale>/<template_name>.subject.txt<root>/<locale>/<template_name>.body.txt- fallback to language-only locale (for example
defromde-DE) - fallback to
en
Example file-template config:
'email_template_locale' => 'de-DE',
'email_template_roots' => [
__DIR__ . '/../../templates/email',
'/opt/myapp/mail-templates',
],Default template example:
templates/email/en/verify_email.subject.txttemplates/email/en/verify_email.body.txt
Default mail notification templates shipped:
verify_emailpassword_reset_requestedpassword_reset_completedadmin_new_user_registered
Template file contents are preformatted text with placeholders:
Please verify your account
Hi {{real_name}},
Your verification token: {{token}}
Optional array fallback when no file template exists:
'email_templates' => [
'verify_email' => [
'subject' => 'Please verify your account',
'text' => "Hi {{real_name}},\n\nYour verification token: {{token}}",
],
],Available placeholders for verify_email:
{{token}}{{verify_link}}{{username}}{{email}}{{real_name}}
Available placeholders for admin_new_user_registered:
{{user_id}}{{username}}{{email}}{{real_name}}{{source_ip}}{{request_id}}
When admin_registration_notify_to is set (array or comma-separated list), admin notifications are emitted on successful registration using the admin_new_user_registered template.
For host-app embedding, the config file can provide a shared PDO instance via pdo.
If pdo is present, the demo router and migration runner reuse it instead of opening a separate DB connection.
This lets the module use the same database/session context as the embedding application.
For a concrete shared-PDO integration example, see:
examples/host_app_bootstrap.php
Run it like this:
php -S 127.0.0.1:8090 examples/host_app_bootstrap.phpIt exposes sample host-mounted routes:
POST /host/auth/registerPOST /host/auth/login
POST /registerPOST /loginPOST /verify-emailPOST /password-reset/requestPOST /password-reset/confirmPOST /totp/enroll/begin(auth + CSRF)POST /totp/enroll/confirm(auth + CSRF)POST /recovery-codes/regenerate(auth + CSRF)POST /step-up/verifyPOST /passkeys/register/begin(auth + CSRF)POST /passkeys/register/finish(auth + CSRF)POST /passkeys/authenticate/begin(CSRF)POST /passkeys/authenticate/finish(CSRF)GET /passkeys/list(auth)POST /passkeys/revoke(auth + CSRF)GET /sessions(auth)POST /sessions/revoke(auth + CSRF)GET /oidc/google/startGET /oidc/google/callback
- Register/login/verify-email/password-reset
- TOTP enroll + recovery code regeneration
- Step-up verification
- Passkey list + revoke
- Sessions/devices list + revoke
- Profile
All POST /ui/* routes require valid CSRF tokens.
Fast security suite:
composer test:securityFull DB-backed security suite (ephemeral MariaDB):
composer test:security:dbFocused WebAuthn-enabled DB path:
composer test:security:db:webauthn- PDO prepared statements
- Argon2id password hashing (preferred)
random_bytes()token generation- Hashed tokens at rest
- Session ID regeneration on login
- CSRF enforcement on state-changing routes
- Generic auth failures (no account enumeration)
- Audit events for critical auth/security actions
- Pluggable risk engine with
allow,require_step_up,deny
Key extension interfaces:
StepUpServiceInterfaceTotpServiceInterfaceRecoveryCodeServiceInterfacePasskeyServiceInterfacePasskeyCeremonyValidatorInterfaceOidcProviderInterfaceEventDispatcherInterface
Primary composition roots:
examples/minimal_router.phpmigrations/run.php
Phase-1 and planned Phase-2 capabilities are implemented in this repository, with DB-backed security regression coverage and CI workflow validation.