@tjoc/auth
v3.0.0
Published
Authentication and authorization package for TJOC platform
Maintainers
Readme
@tjoc/auth
A comprehensive authentication and authorization package for the TJOC platform. Provides secure user authentication, JWT management, 2FA support, and device tracking.
Features
- 🔐 Secure JWT-based authentication
- 👥 User management and role-based access control
- 🔒 Two-factor authentication (TOTP)
- 📱 Device tracking and management
- 🛡️ Rate limiting and brute force protection
- 🔄 Token refresh and blacklisting
- ✉️ Email verification
- 🔑 Password reset functionality
- 📝 Comprehensive audit logging
Installation
# If using npm
npm install @tjoc/auth
# If using yarn
yarn add @tjoc/auth
# If using pnpm
pnpm add @tjoc/authQuick Start
import { initAuthModule, type InitAuthModuleOptions } from '@tjoc/auth';
import { TypeORMUserRepository } from './repositories/typeorm-user.repository';
import { DataSource } from 'typeorm';
// Initialize TypeORM connection
const dataSource = new DataSource({
type: 'postgres',
host: process.env.DB_HOST,
port: parseInt(process.env.DB_PORT || '5432'),
username: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
entities: ['dist/entities/*.js'],
synchronize: false,
});
await dataSource.initialize();
// Configure the auth module
const options: InitAuthModuleOptions = {
config: {
jwtSecret: process.env.JWT_SECRET!,
jwtExpiresIn: 3600, // 1 hour
refreshTokenSecret: process.env.REFRESH_TOKEN_SECRET!,
refreshTokenExpiresIn: 604800, // 7 days
resetPasswordUrl: 'https://your-app.com/reset-password',
verifyEmailUrl: 'https://your-app.com/verify-email',
},
// Provide your TypeORM repository implementation
userRepository: new TypeORMUserRepository(dataSource),
// Redis configuration for token blacklist, sessions, etc.
redis: {
url: process.env.REDIS_URL!,
keyPrefix: 'auth:', // optional
lockout: {
maxAttempts: 3, // optional, default: 3
lockoutDuration: 300, // optional, default: 300 (5 minutes)
},
},
// Optional email configuration
emailConfig: {
from: '[email protected]',
verificationEmailTemplate: 'verify-email', // optional
resetPasswordEmailTemplate: 'reset-password', // optional
},
// Two-factor authentication configuration
twoFactorConfig: {
issuer: 'Your App Name',
algorithm: 'SHA256', // optional, default: SHA256
digits: 6, // optional, default: 6
step: 30, // optional, default: 30 seconds
},
};
// Initialize all auth services
const {
authService,
tokenBlacklistService,
deviceService,
auditService,
twoFactorService,
accountLockoutService,
backupCodesService,
} = initAuthModule(options);
// Login example
const loginResponse = await authService.login({
email: '[email protected]',
password: 'securePassword123',
});
// Register example
const registerResponse = await authService.register({
email: '[email protected]',
password: 'securePassword123',
firstName: 'John',
lastName: 'Doe',
});Two-Factor Authentication
import { TwoFactorService, TwoFactorConfig } from '@tjoc/auth';
// Configure 2FA
const twoFactorConfig: TwoFactorConfig = {
issuer: 'TJOC Platform',
algorithm: 'SHA256',
digits: 6,
step: 30,
};
const twoFactorService = new TwoFactorService(twoFactorConfig);
// Generate secret for new user
const secret = twoFactorService.generateSecret();
// Generate QR code for setup
const qrCode = await twoFactorService.generateQRCode(
'[email protected]',
secret
);
// Verify token
const isValid = twoFactorService.verifyToken(
'123456', // Token from authenticator app
secret
);Rate Limiting
import { RateLimitMiddleware, RateLimitConfig } from '@tjoc/auth';
// Configure rate limiting
const rateLimitConfig: RateLimitConfig = {
points: 5, // Number of attempts
duration: 60, // Per minute
blockDuration: 300, // Block for 5 minutes
};
const rateLimitMiddleware = new RateLimitMiddleware(rateLimitConfig);
// Use in Express route
app.post('/login', rateLimitMiddleware.loginRateLimit, authController.login);Device Tracking
import { DeviceService } from '@tjoc/auth';
const deviceService = new DeviceService();
// Track login from new device
const device = await deviceService.trackLogin(userId, req);
// Get user's devices
const devices = await deviceService.getUserDevices(userId);
// Remove device
await deviceService.removeDevice(userId, deviceId);Security Features
Password Validation
Passwords must meet the following requirements:
- Minimum 8 characters
- At least one uppercase letter
- At least one lowercase letter
- At least one number
- At least one special character
import { validatePassword } from '@tjoc/auth';
const { valid, errors } = validatePassword('password123');
if (!valid) {
console.log(errors); // Array of validation error messages
}Token Blacklisting
import { TokenBlacklistService } from '@tjoc/auth';
const blacklistConfig = {
redisUrl: process.env.REDIS_URL!,
keyPrefix: 'blacklist:',
};
const blacklistService = new TokenBlacklistService(blacklistConfig);
// Blacklist a token
await blacklistService.blacklist(token, expiryInSeconds);
// Check if token is blacklisted
const isBlacklisted = await blacklistService.isBlacklisted(token);Environment Variables
# Database Configuration
DB_HOST=localhost
DB_PORT=5432
DB_USER=postgres
DB_PASSWORD=your-password
DB_NAME=your-database
# Auth Configuration
JWT_SECRET=your-jwt-secret
REFRESH_TOKEN_SECRET=your-refresh-token-secret
# Redis Configuration
REDIS_URL=redis://localhost:6379Audit Logging
import { AuditService, AuditEventType } from '@tjoc/auth';
const auditService = new AuditService();
// Log a successful login
await auditService.log(userId, AuditEventType.LOGIN_SUCCESS, req);
// Retrieve user events
const { events, total } = await auditService.getUserEvents(userId, {
limit: 10,
});
// Search logout events
const { events: logoutEvents } = await auditService.searchEvents({
type: AuditEventType.LOGOUT,
});Middleware Usage
Authentication Middleware
import { AuthMiddleware, UserRole } from '@tjoc/auth';
const authMiddleware = new AuthMiddleware({
jwtSecret: process.env.JWT_SECRET!,
});
// Protect routes
app.get('/profile', authMiddleware.verifyToken, controller.profile);
// Role-based access
app.get(
'/admin',
authMiddleware.verifyToken,
authMiddleware.hasRole([UserRole.ADMIN]),
controller.admin
);CSRF Protection
import { CSRFMiddleware } from '@tjoc/auth';
const csrfMiddleware = new CSRFMiddleware({ secret: process.env.CSRF_SECRET! });
app.use(csrfMiddleware.protect());Session Management
import { SessionMiddleware } from '@tjoc/auth';
const sessionMiddleware = new SessionMiddleware({
secret: process.env.SESSION_SECRET!,
redisUrl: process.env.REDIS_URL!,
});
app.use(sessionMiddleware.initialize());API Reference (Updated)
AuthService
| Method | Description |
| ---------------------------------------------------------------- | ------------------------------------- |
| login(payload: LoginPayload) | Authenticate user and generate tokens |
| register(payload: RegisterPayload) | Register new user |
| refreshToken(payload: RefreshTokenPayload) | Generate new access token |
| logout(refreshToken: string) | Invalidate refresh token |
| resetPassword(payload: ResetPasswordPayload) | Reset user password |
| verifyEmail(payload: VerifyEmailPayload) | Verify user email |
| requestPasswordReset(payload: RequestPasswordResetPayload) | Send password reset link |
| changePassword(userId: string, payload: ChangePasswordPayload) | Change user's password |
TokenBlacklistService
| Method | Description |
| --------------------------------------------- | ------------------------------------ |
| blacklist(token: string, expiresIn: number) | Add a refresh token to the blacklist |
| isBlacklisted(token: string) | Check if a token is blacklisted |
| remove(token: string) | Remove a token from the blacklist |
DeviceService
| Method | Description |
| ------------------------------------------------ | ------------------ |
| trackLogin(userId: string, req: Request) | Track device login |
| getUserDevices(userId: string) | Get user's devices |
| removeDevice(userId: string, deviceId: string) | Remove device |
TwoFactorService
| Method | Description |
| ----------------------------------------------- | --------------------------- |
| generateSecret() | Generate a new TOTP secret |
| generateQRCode(email: string, secret: string) | Generate QR code for setup |
| verifyToken(token: string, secret: string) | Verify TOTP token |
| generateToken(secret: string) | Generate current TOTP token |
AuditService
| Method | Description |
| -------------------------------------------------------------------- | -------------------------- |
| log(userId: string, type: AuditEventType, req: Request, metadata?) | Log an audit event |
| getUserEvents(userId: string, options?) | Retrieve user audit events |
| getEventsByType(type: AuditEventType, options?) | Retrieve events by type |
| searchEvents(query, options?) | Search events with filters |
Validators
| Function | Description |
| ------------------------------------ | ---------------------------- |
| validatePassword(password: string) | Validate password complexity |
Middleware
| Middleware | Description |
| --------------------- | -------------------------------------- |
| AuthMiddleware | JWT verification and role-based access |
| RateLimitMiddleware | Rate limiting for endpoints |
| CSRFMiddleware | CSRF protection |
| SessionMiddleware | Express session with Redis store |
Contributing
Please read CONTRIBUTING.md for details on our code of conduct and the process for submitting pull requests.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Database Integration
The auth package is database-agnostic and uses the Repository pattern. Here's how to implement the UserRepository interface using TypeORM:
import { UserRepository } from '@tjoc/auth';
import { DataSource, Repository } from 'typeorm';
import { User } from '../entities/user.entity';
import { CreateUserPayload } from '@tjoc/types';
// First, define your User entity
@Entity()
export class User {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column({ unique: true })
email: string;
@Column()
password: string;
@Column()
firstName: string;
@Column()
lastName: string;
@Column({ nullable: true })
phoneNumber?: string;
@Column({ default: false })
emailVerified: boolean;
@Column()
role: string;
@CreateDateColumn()
createdAt: Date;
@UpdateDateColumn()
updatedAt: Date;
}
// Then implement the UserRepository interface
export class TypeORMUserRepository implements UserRepository {
private repository: Repository<User>;
constructor(dataSource: DataSource) {
this.repository = dataSource.getRepository(User);
}
async findByEmail(email: string) {
return this.repository.findOne({ where: { email } });
}
async findById(id: string) {
return this.repository.findOne({ where: { id } });
}
async create(userData: CreateUserPayload) {
const user = this.repository.create(userData);
return this.repository.save(user);
}
async updatePassword(id: string, hashedPassword: string) {
await this.repository.update(id, { password: hashedPassword });
}
async updateEmailVerification(id: string, verified: boolean) {
await this.repository.update(id, { emailVerified: verified });
}
async delete(id: string) {
await this.repository.delete(id);
}
}Redis Integration
The package uses Redis for:
- Token blacklisting
- Session management
- Account lockout tracking
- 2FA backup codes storage
Configure Redis through the module initializer:
const { tokenBlacklistService } = initAuthModule({
// ... other options ...
redis: {
url: process.env.REDIS_URL!,
keyPrefix: 'auth:', // Optional prefix for all Redis keys
lockout: {
maxAttempts: 3, // Max failed 2FA attempts
lockoutDuration: 300, // Lockout duration in seconds
},
},
});Email Templates
Passwordless Login Code
- templateId:
passwordless-login - Variables:
code(string): The 6-digit login codeemail(string): The recipient's email address
- Recommended Subject:
Your TJOC Login Code - Sample Body:
Hi,
Your login code is: <strong>{{code}}</strong>
Enter this code in the app or website to sign in. This code will expire in 10 minutes.
If you did not request this, you can ignore this email.
Thanks,
The TJOC Team