vielhuber / simpleauth
Simple php authentication library.
Requires
- php: ^8.5
- firebase/php-jwt: ^7.0.5
- guzzlehttp/guzzle: ^7.10.3
- vielhuber/comparehelper: ^1.1.9
- vielhuber/dbhelper: ^2.4.8
- vielhuber/mailhelper: ^1
- vlucas/phpdotenv: ^5.6.3
- web-auth/webauthn-lib: ^5.3
Requires (Dev)
- phpunit/phpunit: ^13
This package is auto-updated.
Last update: 2026-06-20 07:32:44 UTC
README
🔒 simpleauth 🔒
simpleauth is a simple php based authentication library.
it leverages:
- json web tokens
- bcrypted passwords
- full api
installation
install once with composer:
composer require vielhuber/simpleauth
now simply create the following files inside a new folder called auth inside your public directory:
/auth/index.php
<?php require_once __DIR__ . '/../vendor/autoload.php'; use vielhuber\simpleauth\simpleauth; $auth = new simpleauth(config: __DIR__ . '/../.env', table: 'users', login: 'email', ttl: 1, uuid: false); $auth->init();
/auth/.htaccess
RewriteEngine on
RewriteCond %{HTTP:Authorization} ^(.*)
RewriteRule .* - [e=HTTP_AUTHORIZATION:%1]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^.*$ /auth/index.php [L,QSA]
/.env
create a jwt secret (openssl rand -base64 64 | tr -d '\n' | xclip -selection clipboard)
and populate an .env file:
DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=simpleauth DB_USERNAME=root DB_PASSWORD=root JWT_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
if you want to migrate and seed data, simply run
php auth/index.php migrate php auth/index.php create "david@vielhuber.de" "secret"
and you should be done (a test user 'david@vielhuber.de' with the password 'secret' is created).
you can now fully authenticate with the routes below.
if you want to authenticate via username instead of email, simply change login to 'username'.
if you need uuids instead of integers as your user ids, change uuid to true.
access tokens are valid for one day by default. you can adjust this with ttl. cors is enabled for all origins by default and can be restricted with cors. use cors: true or cors: '*' to allow all origins. Use cors: false to disable cors headers:
$auth = new simpleauth( /* ... */ cors: ['https://example.tld'] );
login throttling is enabled by default: after 5 failed login attempts per login and IP within 15 minutes, /auth/login responds with status 429. You can disable it with throttle: false or adjust the limits with throttle:
$auth = new simpleauth( /* ... */ throttle: [ 'attempts' => 5, 'minutes' => 15, 'table' => 'users_login_attempts' ] );
captcha validation is disabled by default.
the matching captcha token is sent by the frontend on /auth/login.
$auth = new simpleauth( /* ... */ captcha: [ 'provider' => '...', // 'turnstile'|'hcaptcha' 'sitekey' => 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', 'secret' => 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' ] );
passkeys are supported via WebAuthn and are available after running migrate. Browsers require a secure context for passkeys, except on localhost. You can disable passkeys with passkeys: false or adjust the table names with passkeys:
$auth = new simpleauth( /* ... */ passkeys: [ 'table' => 'users_passkeys', 'table_challenge' => 'users_passkeys_challenges' ] );
password reset mails are sent as HTML emails through mailhelper. The reset token is a signed, stateless JWT and no additional database table is required. Configure SMTP through .env:
SMTP_HOST=smtp.example.com SMTP_PORT=587 SMTP_USERNAME=username SMTP_PASSWORD=password SMTP_ENCRYPTION=tls SMTP_FROM_EMAIL=noreply@example.com SMTP_FROM_NAME=simpleauth PASSWORD_RESET_URL=/reset-password
For Microsoft 365 / Exchange SMTP via OAuth, use tenant credentials instead of username/password:
SMTP_HOST=smtp.office365.com SMTP_PORT=587 SMTP_TENANT_ID=tenant-id SMTP_CLIENT_ID=client-id SMTP_CLIENT_SECRET=client-secret SMTP_ENCRYPTION=tls SMTP_FROM_EMAIL=noreply@example.com SMTP_FROM_NAME=simpleauth PASSWORD_RESET_URL=/reset-password
PASSWORD_RESET_URL can be absolute (https://example.com/reset-password) or relative (/reset-password). If it contains {token}, the placeholder is replaced. Otherwise the token is appended as token query parameter.
The password reset flow is:
- Add a "forgot password" form in your application that posts the login field, for example
email, to/auth/password-reset-request. simpleauthsends an email with a signed reset token link toPASSWORD_RESET_URL.- Add a reset page in your application at that URL, for example
/reset-password. - The reset page reads the
tokenquery parameter and shows a form with a new password field. - Submit
tokenandpasswordto/auth/password-reset. simpleauthverifies the token and sets the new password.
You can customize the password reset email with passwordResetMail. Return subject and content. The callback receives the login and the reset link:
$auth = new simpleauth( /* ... */ passwordResetMail: fn(string $login, string $link): array => [ 'subject' => 'Reset your password', 'content' => '<p>Hello ' . htmlspecialchars($login) . ',</p><p><a href="' . htmlspecialchars($link) . '">Set a new password</a></p>' ] );
routes
the following routes are provided automatically:
| route | method | arguments | header | response |
|---|---|---|---|---|
/auth/login |
POST | email password captcha-response | -- | ([ 'success' => true, 'message' => 'auth successful', 'public_message' => '...', 'data' => [ 'access_token' => '...', 'expires_in' => 86400, 'user_id' => 42 ] ], 200) |
/auth/refresh |
POST | -- | Authorization: Bearer token | ([ 'success' => true, 'message' => 'auth successful', 'public_message' => '...', 'data' => [ 'access_token' => '...', 'expires_in' => 86400, 'user_id' => 42 ] ], 200) |
/auth/logout |
POST | -- | Authorization: Bearer token | ([ 'success' => true, 'message' => 'logout successful', 'public_message' => '...' ], 200) |
/auth/check |
POST | access_token | -- | ([ 'success' => true, 'message' => 'valid token', 'public_message' => '...', 'data' => [ 'expires_in' => 86400, 'user_id' => 42, 'client_id' => 7000000 ] ], 200) |
/auth/password-reset-request |
POST | -- | ([ 'success' => true, 'message' => 'password reset requested', 'public_message' => '...' ], 200) |
|
/auth/password-reset |
POST | token password | -- | ([ 'success' => true, 'message' => 'password reset successful', 'public_message' => '...' ], 200) |
/auth/passkey-register-options |
POST | -- | Authorization: Bearer token | ([ 'success' => true, 'message' => 'passkey registration options created', 'public_message' => '...', 'data' => [ 'publicKey' => [] ] ], 200) |
/auth/passkey-register |
POST | credential | Authorization: Bearer token | ([ 'success' => true, 'message' => 'passkey registered', 'public_message' => '...' ], 200) |
/auth/passkey-login-options |
POST | email optional | -- | ([ 'success' => true, 'message' => 'passkey login options created', 'public_message' => '...', 'data' => [ 'publicKey' => [] ] ], 200) |
/auth/passkey-login |
POST | credential | -- | ([ 'success' => true, 'message' => 'auth successful', 'public_message' => '...', 'data' => [ 'access_token' => '...', 'expires_in' => 86400, 'user_id' => 42 ] ], 200) |
/auth/passkey-delete |
POST | id | Authorization: Bearer token | ([ 'success' => true, 'message' => 'passkey deleted', 'public_message' => '...' ], 200) |
tests
php -S localhost:8007 -t auth ./vendor/bin/phpunit
further usage
you can use the following functions inside your own application:
require __DIR__ . '/vendor/autoload.php'; use vielhuber\simpleauth\simpleauth; $auth = new simpleauth(config: __DIR__ . '/../.env', table: 'users', login: 'email', ttl: 1, uuid: false); $auth->isLoggedIn(); $auth->getCurrentUserId(); $auth->migrate(); $auth->getUsers(); $auth->getUser(login: 'david@vielhuber.de'); $auth->createUser(login: 'david@vielhuber.de', password: 'secret2'); $auth->updateUser(login: 'david@vielhuber.de', login_new: 'david@vielhuber.de', password_new: 'secret3'); $auth->setPassword(login: 'david@vielhuber.de', password: 'secret4'); $auth->requestPasswordReset(login: 'david@vielhuber.de'); $token = $auth->createPasswordResetToken(login: 'david@vielhuber.de'); $auth->resetPassword(token: $token, password: 'secret5'); $auth->getPasskeys(login: 'david@vielhuber.de'); $auth->deletePasskey(login: 'david@vielhuber.de', passkey_id: 1); $auth->deleteUser(login: 'david@vielhuber.de');
frontend
if you need a neat frontend library that works together with
simpleauth seemlessly, try out jwtbutler.