Authentication
Keel supports passwordless OTP, magic-link, or both.
Environment toggle
# otp | magic_link | both
AUTH_METHOD=both
Routes
$router->post('/auth/otp/request', [AuthController::class, 'requestOtp']);
$router->post('/auth/otp/verify', [AuthController::class, 'verifyOtp']);
$router->post('/auth/magic/request', [AuthController::class, 'requestMagicLink']);
$router->get('/auth/magic', [AuthController::class, 'verifyMagicLink']);
Current behavior
- OTP: 6-digit code, hashed with
password_hash(), 10-minute expiry. - Magic link: 32-byte token, SHA-256 hash at rest, 15-minute expiry.
- Both flows send mail through the shared Mailer (see the Mailing docs page for SMTP/log setup).
- Both flows rate-limit token issuance to 5 requests per 15 minutes per user.
- Successful sign-in regenerates the session and sets
user_id,user_email, and org/theme session values. - If multi-tenancy is enabled and no org is assigned, login redirects to
/onboarding/organization; otherwise/dashboard.