Authentication
Overview
Nexphant provides session-based authentication with:
- Password hashing
- Session management
- Remember me functionality
- Automatic session regeneration
- Middleware protection
Setup
Enable Middleware
php
use Nexphant\App;
use Nexphant\Server\Middleware\{SessionMiddleware, AuthMiddleware};
$app = App::create();
$app->middleware(SessionMiddleware::class);
$app->middlewareAlias([
'auth' => AuthMiddleware::class,
]);User Model
php
use Nexphant\Database\Model;
use Nexphant\Database\Attributes\*;
#[Table('users')]
class User extends Model
{
#[Id]
public int $id;
#[Email]
#[Unique]
public string $email;
#[Length(min: 3, max: 100)]
public string $name;
#[Hidden]
public string $password;
#[Nullable]
public ?string $rememberToken;
#[CreatedAt]
public DateTimeImmutable $createdAt;
#[UpdatedAt]
public DateTimeImmutable $updatedAt;
}Registration
php
use App\Models\User;
$app->post('/register', function (Request $request) {
$data = $request->json();
// Validate
if (User::query()->where('email', $data['email'])->exists()) {
return ['error' => 'Email already exists'];
}
// Hash password
$data['password'] = password_hash($data['password'], PASSWORD_DEFAULT);
// Create user
$userId = User::query()->insertGetId($data);
// Log in
session()->regenerate();
session()->put('user_id', $userId);
return ['success' => true];
});Login
Basic Login
php
$app->post('/login', function (Request $request) {
$credentials = $request->json();
$user = User::query()
->where('email', $credentials['email'])
->first();
if (!$user || !password_verify($credentials['password'], $user->password)) {
return ['error' => 'Invalid credentials'];
}
// Regenerate session
session()->regenerate();
// Store user ID
session()->put('user_id', $user->id);
return ['success' => true];
});With Remember Me
php
$app->post('/login', function (Request $request) {
$credentials = $request->json();
$remember = $credentials['remember'] ?? false;
$user = User::query()
->where('email', $credentials['email'])
->first();
if (!$user || !password_verify($credentials['password'], $user->password)) {
return ['error' => 'Invalid credentials'];
}
session()->regenerate();
session()->put('user_id', $user->id);
if ($remember) {
$token = bin2hex(random_bytes(32));
User::query()
->where('id', $user->id)
->update(['remember_token' => hash('sha256', $token)]);
cookie()
->make('remember_token', $token)
->maxAge(60 * 60 * 24 * 30) // 30 days
->httpOnly()
->secure();
}
return ['success' => true];
});Logout
php
$app->post('/logout', function () {
$userId = session()->get('user_id');
if ($userId) {
User::query()
->where('id', $userId)
->update(['remember_token' => null]);
}
session()->invalidate();
cookie()->forget('remember_token');
return ['success' => true];
});Auth Helper
Check Authentication
php
if (auth()->check()) {
// User is logged in
}
if (auth()->guest()) {
// User is not logged in
}Get Current User
php
$user = auth()->user();
if ($user) {
echo $user->name;
}User ID
php
$userId = auth()->id();Protected Routes
Using Middleware
php
$app->get('/profile', function () {
$user = auth()->user();
return ['user' => $user];
})->middleware('auth');Route Group
php
$app->group(['middleware' => ['auth']], function ($group) {
$group->get('/profile', fn() => ['user' => auth()->user()]);
$group->get('/settings', fn() => ['settings' => 'page']);
$group->post('/update', fn(Request $req) => ['updated' => true]);
});Manual Check
php
$app->get('/profile', function () {
if (!auth()->check()) {
return ['error' => 'Unauthorized'];
}
return ['user' => auth()->user()];
});Configuration
config/auth.php:
php
return [
'model' => \App\Models\User::class,
'session_key' => 'user_id',
'remember_key' => 'remember_token',
'password_timeout' => 10800, // 3 hours
];Password Reset
Request Reset
php
$app->post('/forgot-password', function (Request $request) {
$email = $request->json('email');
$user = User::query()->where('email', $email)->first();
if (!$user) {
return ['message' => 'If email exists, reset link sent'];
}
$token = bin2hex(random_bytes(32));
// Store token (use separate password_resets table)
DB::table('password_resets')->insert([
'email' => $email,
'token' => hash('sha256', $token),
'created_at' => time(),
]);
// Send email with $token...
return ['message' => 'Reset link sent'];
});Reset Password
php
$app->post('/reset-password', function (Request $request) {
$data = $request->json();
$reset = DB::table('password_resets')
->where('email', $data['email'])
->where('token', hash('sha256', $data['token']))
->first();
if (!$reset || $reset['created_at'] < time() - 3600) {
return ['error' => 'Invalid or expired token'];
}
$hashedPassword = password_hash($data['password'], PASSWORD_DEFAULT);
User::query()
->where('email', $data['email'])
->update(['password' => $hashedPassword]);
DB::table('password_resets')
->where('email', $data['email'])
->delete();
return ['success' => true];
});Two-Factor Authentication
Setup
php
use Nexphant\Auth\TwoFactorAuth;
$app->post('/2fa/enable', function () {
$user = auth()->user();
$secret = TwoFactorAuth::generateSecret();
$qrCode = TwoFactorAuth::getQRCode($user->email, $secret);
User::query()
->where('id', $user->id)
->update(['two_factor_secret' => $secret]);
return [
'secret' => $secret,
'qr_code' => $qrCode,
];
})->middleware('auth');Verify
php
$app->post('/2fa/verify', function (Request $request) {
$user = auth()->user();
$code = $request->json('code');
if (TwoFactorAuth::verify($code, $user->two_factor_secret)) {
session()->put('2fa_verified', true);
return ['success' => true];
}
return ['error' => 'Invalid code'];
})->middleware('auth');Complete Example
php
use Nexphant\App;
use Nexphant\Request;
use Nexphant\Server\Middleware\{SessionMiddleware, AuthMiddleware};
use App\Models\User;
$app = App::create();
// Middleware
$app->middleware(SessionMiddleware::class);
$app->middlewareAlias(['auth' => AuthMiddleware::class]);
// Public routes
$app->post('/register', function (Request $request) {
$data = $request->json();
$data['password'] = password_hash($data['password'], PASSWORD_DEFAULT);
$userId = User::query()->insertGetId($data);
session()->regenerate();
session()->put('user_id', $userId);
return ['success' => true];
});
$app->post('/login', function (Request $request) {
$credentials = $request->json();
$user = User::query()
->where('email', $credentials['email'])
->first();
if (!$user || !password_verify($credentials['password'], $user->password)) {
return ['error' => 'Invalid credentials'];
}
session()->regenerate();
session()->put('user_id', $user->id);
return ['success' => true, 'user' => $user];
});
// Protected routes
$app->group(['middleware' => ['auth']], function ($group) {
$group->get('/profile', function () {
return ['user' => auth()->user()];
});
$group->put('/profile', function (Request $request) {
$data = $request->json();
User::query()
->where('id', auth()->id())
->update($data);
return ['success' => true];
});
$group->post('/logout', function () {
session()->invalidate();
return ['success' => true];
});
});
$app->listen(port: 8080);Security Best Practices
- Always hash passwords with
password_hash() - Regenerate session after login
- Use HTTPS in production
- Set secure cookies (httpOnly, secure, sameSite)
- Implement rate limiting on login
- Use CSRF protection
- Validate email before registration
- Implement password strength requirements
- Add account lockout after failed attempts
- Log authentication events
