Authentication
Khadem provides a comprehensive authentication system with support for JWT and token-based authentication. The system is built with security, flexibility, and ease of use in mind.
Multi-Driver Support
JWT, Token, and extensible custom drivers
Secure by Default
Built-in security features and best practices
Flexible Configuration
Guard-based authentication with multiple providers
AuthManager - Main Authentication Interface
The AuthManager provides a unified interface for all authentication operations. It supports multiple guards and drivers for flexible authentication scenarios.
dart
import 'package:khadem/khadem_dart.dart';
class AuthController {
final AuthManager auth;
AuthController.singleton({String? guard})
: auth = AuthManager(guard: guard);
static AuthController instance = AuthController.singleton();
factory AuthController() => instance;
Future<Map<String, dynamic>> login(Request req, Response res) async {
final data = await req.validate({
'email': 'required|email',
'password': 'required|min:6',
});
final payload = await auth.login(data);
return {
'message': 'Login successful',
'data': {
'token': payload['token'],
'user': payload['user'],
}
};
}
Future<Map<String, dynamic>> register(Request req, Response res) async {
final data = await req.validate({
'name': 'required',
'email': 'required|email',
'password': 'required|min:6|confirmed',
});
data['password'] = HashHelper.hash(data['password']);
final user = User()..fromJson(data);
await user.save();
final payload = await auth.login({
'email': data['email'],
'password': req.input('password'),
});
return {
'message': 'User registered successfully',
'data': {
'token': payload['token'],
'user': user,
}
};
}
}
dart
import 'package:khadem/khadem_dart.dart';
class AuthController {
static Future<Map<String, dynamic>> login(Request req, Response res) async {
final data = await req.validate({
'email': 'required|email',
'password': 'required|min:6',
});
final auth = AuthManager();
final payload = await auth.login(data);
res.sendJson({
'message': 'Login successful',
'data': {
'token': payload['token'],
'user': User()..fromJson(payload['user']),
}
});
}
}
Web Authentication
For web applications, Khadem provides session-based authentication with WebAuthService and WebAuthMiddleware for protecting routes and managing user sessions.
dart
import 'package:khadem/khadem_dart.dart';
class WebAuthController {
WebAuthController.singleton();
static WebAuthController instance = WebAuthController.singleton();
factory WebAuthController() => instance;
Future<void> showLogin(Request req, Response res) async {
await res.view('login');
}
Future<void> showRegister(Request req, Response res) async {
await res.view('register');
}
Future<void> login(Request req, Response res) async {
final data = await req.validate({
'email': 'required|email',
'password': 'required|min:6',
'remember': 'nullable|boolean',
});
final webAuth = WebAuthService();
await webAuth.attemptLogin({
'email': data['email'],
'password': data['password'],
}, remember: data['remember'] == true);
final intended = req.input('intended') ?? '/dashboard';
await res.redirect(intended);
}
Future<void> register(Request req, Response res) async {
final data = await req.validate({
'name': 'required',
'email': 'required|email',
'password': 'required|min:6|confirmed',
});
data['password'] = HashHelper.hash(data['password']);
final user = User()..fromJson(data);
await user.save();
final webAuth = WebAuthService();
await webAuth.attemptLogin({
'email': data['email'],
'password': req.input('password'),
}, remember: false);
await res.redirect('/dashboard');
}
Future<void> dashboard(Request req, Response res) async {
final webAuth = WebAuthService();
final isAuthenticated = await webAuth.isAuthenticated(req);
if (!isAuthenticated) {
return res.redirect('/login');
}
final user = User()..fromJson((await webAuth.getCurrentUser(req)) ?? {});
await res.view('dashboard', data: {'user': user.toJson()});
}
Future<void> logout(Request req, Response res) async {
final webAuth = WebAuthService();
await webAuth.logout(req, res);
await res.redirect('/login');
}
}
dart
import 'package:khadem/khadem_dart.dart';
class WebAuthMiddleware {
static Middleware auth({
String redirectTo = '/login',
List<String> except = const [],
}) {
final authService = WebAuthService();
return Middleware((Request req, Response res, NextFunction next) async {
if (_isExcluded(req.path, except)) {
return next();
}
if (!authService.isAuthenticated(req)) {
req.session.set('url.intended', req.uri.toString());
req.session.flash('message', 'Please log in to continue');
res.redirect(redirectTo);
return;
}
await _ensureUserContext(req, authService, redirectTo);
return next();
});
}
static Middleware guest({
String redirectTo = '/dashboard',
List<String> except = const [],
}) {
final authService = WebAuthService();
return Middleware((Request req, Response res, NextFunction next) async {
if (_isExcluded(req.path, except)) {
return next();
}
if (authService.isAuthenticated(req)) {
res.redirect(redirectTo);
return;
}
return next();
});
}
static bool _isExcluded(String path, List<String> except) {
return except.any((route) => path.startsWith(route));
}
static Future<void> _ensureUserContext(
Request req,
WebAuthService authService,
String redirectTo,
) async {
if (req.user == null) {
final user = await authService.getCurrentUser(req);
if (user != null) {
req.setUser(user);
}
}
}
}
Authentication Middleware
Protect your routes with authentication middleware. The AuthMiddleware automatically validates Bearer tokens and attaches user data to requests.
dart
import 'package:khadem/khadem_dart.dart';
class AuthMiddleware extends Middleware {
AuthMiddleware() : super(_handleAuth);
static Future<void> _handleAuth(Request req, Response res, NextFunction next) async {
try {
final authHeader = _extractAuthHeader(req);
final token = _extractBearerToken(authHeader);
final user = await _verifyToken(token);
_attachUserToRequest(req, user);
await next();
} catch (error) {
throw AuthException('Authentication failed: ${error.toString()}');
}
}
static String _extractAuthHeader(Request request) {
final authHeader = request.header('authorization');
if (authHeader == null || authHeader.isEmpty) {
throw AuthException('Missing authorization header');
}
return authHeader;
}
static String _extractBearerToken(String authHeader) {
if (!authHeader.startsWith('Bearer ')) {
throw AuthException('Invalid authorization header format');
}
final token = authHeader.replaceFirst('Bearer ', '').trim();
if (token.isEmpty) {
throw AuthException('Empty token provided');
}
return token;
}
static Future<Map<String, dynamic>> _verifyToken(String token) async {
final authManager = Khadem.container.resolve<AuthManager>();
return authManager.verify(token);
}
static void _attachUserToRequest(Request request, Map<String, dynamic> user) {
request.setAttribute('user', user);
request.setAttribute('userId', user['id']);
request.setAttribute('isAuthenticated', true);
}
}
dart
// routes/web.dart
import 'package:khadem/khadem_dart.dart';
void defineRoutes() {
// Public routes
Route.get('/login', AuthController.showLoginForm);
Route.post('/login', AuthController.login);
Route.get('/register', AuthController.showRegister);
Route.post('/register', AuthController.register);
// API routes with AuthMiddleware
Route.group(() {
Route.get('/api/profile', AuthController.profile);
Route.put('/api/profile', AuthController.updateProfile);
Route.post('/api/logout', AuthController.logout);
}, middleware: [AuthMiddleware()]);
// Web routes with WebAuthMiddleware
Route.group(() {
Route.get('/dashboard', WebAuthController.dashboard);
Route.get('/chat', WebAuthController.chat);
}, middleware: [WebAuthMiddleware.auth()]);
}
Guards and Authentication Drivers
Khadem supports multiple authentication guards and drivers. Guards define authentication contexts, while drivers handle the actual authentication logic.
dart
import 'package:khadem/khadem_dart.dart';
// Using different guards
class MultiGuardController {
static Future<Map<String, dynamic>> adminLogin(Request req, Response res) async {
final adminAuth = AuthManager(guard: 'admins');
final data = await req.validate({
'email': 'required|email',
'password': 'required|min:6',
});
final result = await adminAuth.login(data);
res.sendJson({
'message': 'Admin login successful',
'data': {
'token': result['token'],
'user': result['user'],
'guard': 'admins',
}
});
}
static Future<Map<String, dynamic>> userLogin(Request req, Response res) async {
final userAuth = AuthManager(guard: 'users');
final data = await req.validate({
'email': 'required|email',
'password': 'required|min:6',
});
final result = await userAuth.login(data);
res.sendJson({
'message': 'User login successful',
'data': {
'token': result['token'],
'user': result['user'],
'guard': 'users',
}
});
}
}
dart
import 'package:khadem/khadem_dart.dart';
class JWTAuthController {
static Future<Map<String, dynamic>> login(Request req, Response res) async {
final data = await req.validate({
'email': 'required|email',
'password': 'required|min:6',
});
final jwtService = JWTAuthService.create('users');
final result = await jwtService.attemptLogin(data);
res.sendJson({
'message': 'JWT login successful',
'data': {
'token': result['access_token'],
'user': result['user'],
'expires_in': result['expires_in'],
}
});
}
}
Token Management
Khadem provides comprehensive token management including refresh tokens, token verification, and secure token generation.
dart
import 'package:khadem/khadem_dart.dart';
class TokenController {
static Future<Map<String, dynamic>> refreshToken(Request req, Response res) async {
final refreshToken = req.input('refresh_token');
if (refreshToken == null || refreshToken.isEmpty) {
return res.status(400).sendJson({
'error': 'Refresh token is required'
});
}
final auth = AuthManager();
final result = await auth.refreshAccessToken(refreshToken);
res.sendJson({
'message': 'Token refreshed successfully',
'data': {
'access_token': result['access_token'],
'refresh_token': result['refresh_token'],
'token_type': result['token_type'],
'expires_in': result['expires_in'],
}
});
}
}
dart
import 'package:khadem/khadem_dart.dart';
class AuthVerificationController {
static Future<Map<String, dynamic>> verifyToken(Request req, Response res) async {
final token = req.header('authorization')?.replaceFirst('Bearer ', '');
if (token == null || token.isEmpty) {
return res.status(401).sendJson({
'error': 'Token is required'
});
}
final auth = AuthManager();
final user = await auth.verify(token);
res.sendJson({
'message': 'Token is valid',
'data': {
'user': user,
'valid': true,
}
});
}
}
Error Handling
Proper error handling is crucial for authentication. Khadem provides specific exceptions and comprehensive error responses.
dart
import 'package:khadem/khadem_dart.dart';
class AuthErrorHandler {
static Future<Map<String, dynamic>> handleAuthError(Request req, dynamic error) async {
if (error is AuthException) {
final statusCode = error.statusCode ?? 401;
return {
'success': false,
'error': error.message,
'code': error.code ?? 'AUTH_ERROR',
'status_code': statusCode,
};
}
// Handle other authentication-related errors
if (error.toString().contains('token')) {
return {
'success': false,
'error': 'Authentication token error',
'code': 'TOKEN_ERROR',
'status_code': 401,
};
}
if (error.toString().contains('credentials')) {
return {
'success': false,
'error': 'Invalid credentials',
'code': 'INVALID_CREDENTIALS',
'status_code': 401,
};
}
return {
'success': false,
'error': 'Authentication failed',
'code': 'AUTH_FAILED',
'status_code': 500,
};
}
}
// Usage in controller
class AuthController {
static Future<Map<String, dynamic>> login(Request req, Response res) async {
try {
final data = await req.validate({
'email': 'required|email',
'password': 'required|min:6',
});
final auth = AuthManager();
final result = await auth.login(data);
res.sendJson({
'success': true,
'data': result,
});
} catch (error) {
final errorResponse = await AuthErrorHandler.handleAuthError(req, error);
res.status(errorResponse['status_code']).sendJson(errorResponse);
}
}
}