7.7 KiB
7.7 KiB
@feature/auth Playbook
1. Overview
Handles Authentication (OTP, Magic Link, Federated), Session Management, and Biometrics with risk-adaptive security.
Key Features (per FRD):
- F.ID.001: Login, Registration, and Forgot Password flows
- F.ID.002: Configurable verification (OTP, Email, Magic Links)
- F.ID.003: Secure session token storage and rotation
- F.ID.004: Device biometrics integration (FaceID/TouchID/Android Biometrics)
- F.ID.005: Configurable "Remember Me" duration
- F.ID.006: Enhanced Magic Link security with nonce and expiry
- F.ID.007: Federated Login connectors (Google, Apple)
2. Setup & Dependencies
Required Core SDKs:
@core/security- DPoP key generation and signing@core/trust- Runtime Risk Score; triggers Step-Up MFA if score is high@core/policy- Risk-adaptive policy checks@core/storage- Encrypted session storage
Installation:
# Install auth feature layers
pnpm add @feature/auth/domain @feature/auth/data @feature/auth/ui-rn
# Peer dependencies (automatically resolved in monorepo)
# @core/security @core/trust @core/policy @core/storage
3. Core Workflow: DPoP Login and Risk Assessment
sequenceDiagram
participant App
participant Auth as @feature/auth
participant Trust as @core/trust
participant Security as @core/security
participant Policy as @core/policy
participant BFF
App->>Auth: login(credentials)
Auth->>Trust: calculateRiskScore()
Trust-->>Auth: { score: 45, signals: {...} }
Auth->>Security: initializeDPoP()
Security-->>Auth: publicKey
Auth->>BFF: exchangeCredentials(creds, pubKey)
BFF-->>Auth: session + tokens
alt Risk Score > Threshold
Auth->>Policy: check('step-up-mfa', context)
Policy-->>Auth: requires_verification: true
Auth-->>App: { success: true, requiresStepUp: true }
else Low Risk
Auth-->>App: { success: true, session }
end
4. Integration Points
@core/security Integration
// DPoP key generation and signing
const publicKey = await this.authRepository.initializeDPoP();
const signedProof = await this.securityCore.signDPoPProof('POST', '/auth/login', accessToken);
@core/trust Integration
// Risk assessment for adaptive authentication
const { score, signals } = await this.trustRepository.calculateRiskScore();
const requiresStepUp = this.shouldRequireStepUp(score, signals);
@core/policy Integration
// Risk-adaptive policy checks
const allowed = await this.policyClient.check('login', 'User', {
riskScore: 60,
deviceSignals: signals
});
5. Policy Enforcement Examples
Risk-Adaptive Login:
// Low risk (score < 50): Standard login
await policyClient.check('login', 'User', { riskScore: 35 }); // → true
// Medium risk (50-75): Email verification
await policyClient.check('login', 'User', { riskScore: 65 }); // → requires email MFA
// High risk (75+): OTP + Device attestation
await policyClient.check('login', 'User', { riskScore: 85 }); // → requires OTP + attestation
Organization Access:
// Check organization membership with role-based permissions
await policyClient.check('access-org', 'Organization', {
orgId: 'org-123',
userRole: 'member',
riskScore: 40
});
6. API Usage Examples
Basic Login Flow
import { LoginUseCase } from '@feature/auth/domain';
import { AuthRepository } from '@feature/auth/data';
const authRepo = new AuthRepository(securityCore, bffClient);
const trustRepo = new TrustRepository(trustCore);
const loginUseCase = new LoginUseCase(authRepo, trustRepo, config);
const result = await loginUseCase.execute({
identifier: 'user@example.com',
password: 'secure_password',
deviceId: 'device-uuid'
});
if (result.success) {
if (result.requiresStepUp) {
// Handle step-up MFA flow
console.log('Additional verification required:', result.verificationMethod);
} else {
// Login successful
console.log('User session:', result.session);
}
}
Biometric Authentication
import { BiometricUseCase } from '@feature/auth/domain';
const biometricUseCase = new BiometricUseCase(authRepo, biometricConfig);
const result = await biometricUseCase.authenticate({
promptMessage: 'Authenticate to access LynkedUp',
fallbackToPassword: true
});
Magic Link Flow
// Generate magic link
const magicLink = await authRepo.generateMagicLink('user@example.com');
// Verify magic link (typically called from deep link handler)
const result = await loginUseCase.executeWithMagicLink(token, nonce);
7. Configuration
const authConfig: AuthConfig = {
requireEmailVerification: true,
requirePhoneVerification: false,
biometrics: {
enabled: true,
fallbackToPassword: true,
promptMessage: 'Authenticate with LynkedUp'
},
rememberMeDays: 30,
maxLoginAttempts: 5,
lockoutDurationMinutes: 15
};
8. Error Handling
// Standard error codes returned by AuthResult
switch (result.errorCode) {
case 'INVALID_CREDENTIALS':
// Handle invalid login
break;
case 'ACCOUNT_LOCKED':
// Handle account lockout
break;
case 'VERIFICATION_REQUIRED':
// Handle unverified account
break;
case 'DEVICE_NOT_TRUSTED':
// Handle untrusted device
break;
case 'POLICY_VIOLATION':
// Handle policy-based denial
break;
}
9. Testing Strategy
Unit Tests
// Domain layer testing (LoginUseCase)
describe('LoginUseCase', () => {
it('should require step-up for high risk score', async () => {
mockTrustRepo.calculateRiskScore.mockResolvedValue({ score: 85, signals: {} });
const result = await loginUseCase.execute(validCredentials);
expect(result.requiresStepUp).toBe(true);
});
});
Contract Tests
// Data layer testing against mocked BFF
import { setupServer } from 'msw/node';
import { graphql } from 'msw';
const server = setupServer(
graphql.mutation('Login', (req, res, ctx) => {
return res(ctx.data({
login: {
accessToken: 'mock-token',
user: mockUser
}
}));
})
);
10. Security Notes
Critical Security Requirements:
- Private keys MUST remain in the Secure Enclave/TEE
- Magic links MUST enforce nonce and expiry (see F.ID.006)
- DPoP proofs MUST be bound to specific HTTP requests
- Session tokens MUST be stored in hardware-backed keychain
- Step-up MFA triggers MUST be policy-driven, not hardcoded
Risk Signals Handling:
- Root/Jailbreak detection → Immediate step-up required
- Device attestation failure → Block access + notify admin
- Geolocation deviation → Email verification required
- New device → SMS OTP required
11. Troubleshooting
Common Issues:
-
"SecurityCore must be initialized"
- Ensure
securityCore.initialize()is called before auth operations
- Ensure
-
"DPoP key generation failed"
- Verify hardware-backed storage is available
- Check device security settings (passcode/biometrics enabled)
-
"Policy evaluation failed"
- Verify policy bundles are cached locally
- Check network connectivity for policy updates
-
Biometric authentication unavailable
- Verify device biometric enrollment
- Check app permissions for biometric access
12. Performance Considerations
- Key Operations: DPoP key generation (one-time, ~100ms)
- Risk Assessment: Device evaluation (~50-200ms depending on signals)
- Policy Evaluation: Local cache lookup (~1-5ms)
- Session Storage: Keychain operations (~10-50ms)
Optimization Tips:
- Cache risk assessment results for 5-10 minutes
- Pre-warm DPoP keys during app initialization
- Batch policy evaluations when possible