First commit

This commit is contained in:
Sachin
2025-12-16 22:26:18 +05:30
commit 03ed187ebe
122 changed files with 68601 additions and 0 deletions

View File

@@ -0,0 +1,22 @@
{
"name": "@feature/auth/domain",
"version": "1.0.0",
"description": "Authentication domain logic - pure business rules and use cases",
"main": "./src/index.ts",
"types": "./src/index.ts",
"scripts": {
"build": "nx build",
"test": "nx test",
"lint": "nx lint",
"typecheck": "nx typecheck"
},
"dependencies": {
"uuid": "^9.0.1"
},
"devDependencies": {
"@types/uuid": "^9.0.7"
},
"nx": {
"tags": ["scope:feature", "type:domain", "platform:shared"]
}
}

View File

@@ -0,0 +1,53 @@
export interface User {
id: string;
email: string;
phoneNumber?: string;
firstName: string;
lastName: string;
isEmailVerified: boolean;
isPhoneVerified: boolean;
createdAt: string;
lastLoginAt?: string;
profilePictureUrl?: string;
organizations: UserOrganization[];
preferences: UserPreferences;
}
export interface UserOrganization {
orgId: string;
orgName: string;
role: string;
permissions: string[];
joinedAt: string;
status: 'active' | 'suspended' | 'pending';
}
export interface UserPreferences {
language: string;
timezone: string;
theme: 'light' | 'dark' | 'system';
notifications: NotificationPreferences;
}
export interface NotificationPreferences {
email: boolean;
push: boolean;
sms: boolean;
marketing: boolean;
}
export interface AuthResult {
success: boolean;
session?: any;
requiresVerification?: boolean;
verificationMethod?: VerificationMethod;
errorCode?: string;
errorMessage?: string;
nextSteps?: string[];
}
export type VerificationMethod =
| { type: 'otp'; target: string }
| { type: 'email'; target: string }
| { type: 'biometric' }
| { type: 'magic_link'; target: string };

View File

@@ -0,0 +1,20 @@
export const AuthDomain = {};
import { LoginUseCase } from './usecases/LoginUseCase';
import { RegistrationUseCase } from './usecases/RegistrationUseCase';
import { SessionUseCase } from './usecases/SessionUseCase';
import { BiometricUseCase } from './usecases/BiometricUseCase';
export { LoginUseCase, RegistrationUseCase, SessionUseCase, BiometricUseCase };
export type {
IAuthRepository,
ITrustRepository,
Credentials,
UserSession,
BiometricConfig,
AuthConfig
} from './interfaces';
export type {
User,
AuthResult,
VerificationMethod
} from './entities';

View File

@@ -0,0 +1,76 @@
import type { User, AuthResult } from './entities';
/**
* Repository interface that the data layer must implement
* Following clean architecture principles - domain defines the contract
*/
export interface IAuthRepository {
// F.ID.004: DPoP initialization
initializeDPoP(): Promise<string>;
// F.ID.001: Login flows
exchangeCredentialsForToken(creds: Credentials, pubKey: string): Promise<UserSession>;
// F.ID.002: Verification flows
sendOTPVerification(phoneNumber: string): Promise<void>;
verifyOTP(phoneNumber: string, code: string): Promise<boolean>;
sendEmailVerification(email: string): Promise<void>;
verifyEmail(email: string, token: string): Promise<boolean>;
// Magic Links (F.ID.006 - Enhanced security)
generateMagicLink(email: string): Promise<string>;
verifyMagicLink(token: string, nonce: string): Promise<UserSession>;
// F.ID.007: Federated login
authenticateWithProvider(provider: 'google' | 'apple', token: string): Promise<UserSession>;
// Session management
storeSession(session: UserSession): Promise<void>;
getSession(): Promise<UserSession | null>;
refreshSession(refreshToken: string): Promise<UserSession>;
revokeSession(): Promise<void>;
// F.ID.005: Remember me functionality
enableRememberMe(duration: number): Promise<void>;
disableRememberMe(): Promise<void>;
}
/**
* Trust/Risk assessment interface
*/
export interface ITrustRepository {
calculateRiskScore(): Promise<{ score: number; signals: Record<string, any> }>;
performDeviceAttestation(): Promise<boolean>;
}
export interface Credentials {
identifier: string; // email or phone
password?: string;
biometricSignature?: string;
deviceId: string;
}
export interface UserSession {
userId: string;
accessToken: string;
refreshToken: string;
expiresAt: string;
user: User;
riskScore?: number;
requiresStepUp?: boolean;
}
export interface BiometricConfig {
enabled: boolean;
fallbackToPassword: boolean;
promptMessage: string;
}
export interface AuthConfig {
requireEmailVerification: boolean;
requirePhoneVerification: boolean;
biometrics: BiometricConfig;
rememberMeDays: number;
maxLoginAttempts: number;
lockoutDurationMinutes: number;
}

View File

@@ -0,0 +1,5 @@
export class BiometricUseCase {
async verify(signature: string) {
return false;
}
}

View File

@@ -0,0 +1,177 @@
import type { IAuthRepository, ITrustRepository, Credentials, UserSession, AuthConfig } from '../interfaces';
import type { AuthResult } from '../entities';
/**
* Login Use Case - Pure business logic
* Orchestrates the login flow including risk assessment and DPoP initialization
*
* Features implemented (per FRD):
* - F.ID.001: Login flows
* - F.ID.004: DPoP integration
* - Risk-adaptive authentication
* - Step-up MFA based on risk score
*/
export class LoginUseCase {
constructor(
private authRepository: IAuthRepository,
private trustRepository: ITrustRepository,
private config: AuthConfig
) {}
/**
* Execute login flow with risk assessment
*/
async execute(credentials: Credentials): Promise<AuthResult> {
try {
// 1. Risk Assessment (F.TR.004 from Trust SDK)
const { score: riskScore, signals } = await this.trustRepository.calculateRiskScore();
// 2. Initialize DPoP (F.ID.004 / F.SC.004)
const publicKey = await this.authRepository.initializeDPoP();
// 3. Attempt authentication
const session = await this.authRepository.exchangeCredentialsForToken(credentials, publicKey);
// 4. Enhance session with risk information
const enhancedSession: UserSession = {
...session,
riskScore,
requiresStepUp: this.shouldRequireStepUp(riskScore, signals)
};
// 5. Store session
await this.authRepository.storeSession(enhancedSession);
// 6. Check if step-up authentication is required
if (enhancedSession.requiresStepUp) {
return {
success: true,
session: enhancedSession,
requiresVerification: true,
verificationMethod: this.determineStepUpMethod(signals),
nextSteps: ['Complete additional verification to proceed']
};
}
// 7. Enable Remember Me if configured
if (this.config.rememberMeDays > 0) {
await this.authRepository.enableRememberMe(this.config.rememberMeDays);
}
return {
success: true,
session: enhancedSession
};
} catch (error) {
return this.handleLoginError(error);
}
}
/**
* Biometric login flow
*/
async executeWithBiometrics(biometricSignature: string, deviceId: string): Promise<AuthResult> {
const credentials: Credentials = {
identifier: 'biometric',
biometricSignature,
deviceId
};
return this.execute(credentials);
}
/**
* Magic link login flow (F.ID.006)
*/
async executeWithMagicLink(token: string, nonce: string): Promise<AuthResult> {
try {
const session = await this.authRepository.verifyMagicLink(token, nonce);
await this.authRepository.storeSession(session);
return {
success: true,
session
};
} catch (error) {
return this.handleLoginError(error);
}
}
/**
* Federated login flow (F.ID.007)
*/
async executeWithProvider(provider: 'google' | 'apple', token: string): Promise<AuthResult> {
try {
const session = await this.authRepository.authenticateWithProvider(provider, token);
await this.authRepository.storeSession(session);
return {
success: true,
session
};
} catch (error) {
return this.handleLoginError(error);
}
}
private shouldRequireStepUp(riskScore: number, signals: Record<string, any>): boolean {
// Risk-based step-up logic
if (riskScore > 75) return true;
if (signals.isRooted || signals.isEmulator) return true;
if (signals.attestationFailed) return true;
if (signals.geoDeviation && riskScore > 50) return true;
return false;
}
private determineStepUpMethod(signals: Record<string, any>) {
// Determine the most appropriate step-up method based on risk signals
if (signals.suspiciousLocation) {
return { type: 'otp' as const, target: 'phone' };
}
if (signals.newDevice) {
return { type: 'email' as const, target: 'email' };
}
// Default to biometric if available
return { type: 'biometric' as const };
}
private handleLoginError(error: any): AuthResult {
console.error('Login failed:', error);
// Map specific errors to user-friendly messages
if (error.code === 'INVALID_CREDENTIALS') {
return {
success: false,
errorCode: 'INVALID_CREDENTIALS',
errorMessage: 'Invalid email or password'
};
}
if (error.code === 'ACCOUNT_LOCKED') {
return {
success: false,
errorCode: 'ACCOUNT_LOCKED',
errorMessage: 'Account is temporarily locked due to multiple failed attempts'
};
}
if (error.code === 'VERIFICATION_REQUIRED') {
return {
success: false,
requiresVerification: true,
verificationMethod: error.verificationMethod,
errorMessage: 'Account verification required'
};
}
return {
success: false,
errorCode: 'UNKNOWN_ERROR',
errorMessage: 'An unexpected error occurred'
};
}
}

View File

@@ -0,0 +1,5 @@
export class RegistrationUseCase {
async execute(payload: any) {
return { success: true };
}
}

View File

@@ -0,0 +1,5 @@
export class SessionUseCase {
async getCurrent(sessionId: string) {
return null;
}
}