@haykal/auth-backend
v1.0.0
Published
> Complete authentication module for NestJS — JWT-based auth with registration, login, email verification, password reset, session management, and account lockout.
Downloads
54
Readme
@haykal/auth-backend
Complete authentication module for NestJS — JWT-based auth with registration, login, email verification, password reset, session management, and account lockout.
Installation
pnpm add @haykal/auth-backendPeer dependencies: @nestjs/jwt, @nestjs/passport, passport-jwt, bcrypt
Configuration
forRoot() Options
import { AuthModule } from '@haykal/auth-backend';
@Module({
imports: [
AuthModule.forRoot({
jwt: {
secret: process.env.JWT_SECRET,
accessTokenExpiration: '15m',
refreshTokenExpiration: '7d',
},
password: {
saltRounds: 10,
minLength: 8,
requireUppercase: true,
requireLowercase: true,
requireNumbers: true,
requireSpecialChars: false,
resetTokenTtlSeconds: 3600,
},
registration: {
enabled: true,
requireEmailVerification: false,
},
lockout: {
enabled: true,
maxAttempts: 5,
durationSeconds: 900,
},
}),
],
})
export class AppModule {}Configuration Reference
| Property | Type | Required | Default | Description |
| --------------------------------------- | --------- | -------- | ------- | --------------------------------------- |
| jwt.secret | string | Yes | — | HMAC signing secret |
| jwt.accessTokenExpiration | string | Yes | — | e.g. '15m', '1h' |
| jwt.refreshTokenExpiration | string | No | '7d' | Refresh token TTL |
| password.saltRounds | number | Yes | — | bcrypt rounds |
| password.minLength | number | Yes | — | Minimum password length |
| password.requireUppercase | boolean | Yes | — | Require uppercase letter |
| password.requireLowercase | boolean | Yes | — | Require lowercase letter |
| password.requireNumbers | boolean | Yes | — | Require digit |
| password.requireSpecialChars | boolean | Yes | — | Require special character |
| password.resetTokenTtlSeconds | number | No | 3600 | Password reset token TTL |
| registration.enabled | boolean | Yes | — | Allow new registrations |
| registration.requireEmailVerification | boolean | No | false | Require email verification before login |
| lockout.enabled | boolean | No | false | Enable account lockout |
| lockout.maxAttempts | number | No | 5 | Failed attempts before lockout |
| lockout.durationSeconds | number | No | 900 | Lockout duration (15 min) |
Key Exports
| Export | Type | Description |
| ----------------- | ------------- | ----------------------------------------------------- |
| AuthModule | NestJS Module | Main module with forRoot() / forRootAsync() |
| AUTH_CONFIG | Symbol | Inject the auth config object |
| AuthService | Service | Core auth operations (register, login, refresh, etc.) |
| PasswordService | Service | Password hashing, comparison, and validation |
| TokenService | Service | JWT and opaque token generation/verification |
| SessionService | Service | Session listing and revocation |
| JwtAuthGuard | Guard | Global JWT guard — auto-protects all routes |
| @Public() | Decorator | Bypass JWT auth on specific routes |
| @CurrentUser() | Decorator | Extract authenticated user from request |
Entities
| Export | Description |
| -------------------- | ------------------------------------------------------------- |
| RefreshTokenEntity | Stores refresh token hashes with device info and expiration |
| UserEntity | Re-exported from @haykal/user-management-backend |
| AUTH_ENTITIES | Entity array for migration discovery ([RefreshTokenEntity]) |
Domain Errors
| Error | Code | Status | Description |
| --------------------------- | ----------------------------- | ------ | ------------------------------ |
| InvalidCredentialsError | AUTH_INVALID_CREDENTIALS | 401 | Wrong email or password |
| EmailAlreadyExistsError | AUTH_EMAIL_ALREADY_EXISTS | 409 | Email already registered |
| RegistrationDisabledError | AUTH_REGISTRATION_DISABLED | 403 | Registration turned off |
| WeakPasswordError | AUTH_WEAK_PASSWORD | 422 | Password fails strength rules |
| InvalidTokenError | AUTH_INVALID_TOKEN | 401 | Token invalid or expired |
| AccountLockedError | AUTH_ACCOUNT_LOCKED | 429 | Too many failed login attempts |
| EmailNotVerifiedError | AUTH_EMAIL_NOT_VERIFIED | 403 | Email needs verification |
| EmailAlreadyVerifiedError | AUTH_EMAIL_ALREADY_VERIFIED | 409 | Email already verified |
| SessionNotFoundError | AUTH_SESSION_NOT_FOUND | 404 | Session not found or revoked |
Domain Events
| Event | Payload |
| --------------------------------- | -------------------------------------------- |
| UserRegisteredEvent | userId, email |
| UserLoggedInEvent | userId, email, ipAddress, deviceInfo |
| UserLoggedOutEvent | userId |
| EmailVerificationRequestedEvent | userId, email, token |
| EmailVerifiedEvent | userId, email |
| PasswordResetRequestedEvent | userId, email, token |
| PasswordResetEvent | userId |
| PasswordChangedEvent | userId |
| AccountLockedEvent | userId, failedAttempts |
| AccountUnlockedEvent | userId |
| SessionRevokedEvent | userId, sessionId |
API Endpoints
All endpoints are under /api/auth. Routes marked Public bypass JWT auth.
| Method | Path | Auth | Description |
| -------- | --------------------------- | ------ | ------------------------------------------- |
| POST | /auth/register | Public | Register a new user |
| POST | /auth/login | Public | Login with email and password |
| POST | /auth/refresh | Public | Refresh access token |
| POST | /auth/logout | JWT | Logout current session |
| POST | /auth/revoke-all | JWT | Revoke all sessions |
| GET | /auth/me | JWT | Get current user profile |
| POST | /auth/verify-email | Public | Verify email address with token |
| POST | /auth/resend-verification | Public | Resend verification email |
| POST | /auth/forgot-password | Public | Request password reset |
| POST | /auth/reset-password | Public | Reset password with token |
| POST | /auth/change-password | JWT | Change password (requires current password) |
| GET | /auth/sessions | JWT | List active sessions |
| DELETE | /auth/sessions/:id | JWT | Revoke specific session |
| DELETE | /auth/sessions | JWT | Revoke all other sessions |
Usage Examples
Protecting Routes
All routes are JWT-protected by default. Use @Public() to opt out:
import { Public, CurrentUser } from '@haykal/auth-backend';
import { UserEntity } from '@haykal/user-management-backend';
@Controller('items')
export class ItemsController {
@Get()
@Public()
listPublicItems() {
// No auth required
}
@Post()
createItem(@CurrentUser() user: UserEntity) {
// user is the authenticated user
return this.service.create(user.id, dto);
}
}Listening to Auth Events
import { OnDomainEvent } from '@haykal/core-backend';
import {
UserRegisteredEvent,
PasswordResetRequestedEvent,
} from '@haykal/auth-backend';
@Injectable()
export class AuthEventListener {
@OnDomainEvent(UserRegisteredEvent)
async onRegistered(event: UserRegisteredEvent) {
// Send welcome email
}
@OnDomainEvent(PasswordResetRequestedEvent)
async onPasswordReset(event: PasswordResetRequestedEvent) {
// Send reset email with event.token
}
}Related Packages
@haykal/auth-client— React Query hooks for auth operations@haykal/auth-ui— Pre-built auth UI components and screens@haykal/user-management-backend— User entity and CRUD operations@haykal/core-backend— Base infrastructure (errors, events, guards)
Further Reading
- API Reference — Full endpoint listing
- Architecture Overview — System design and module composition
- Backend Style Guide — Coding conventions
