First commit
This commit is contained in:
279
packages/feature-auth/README.playbook.md
Normal file
279
packages/feature-auth/README.playbook.md
Normal file
@@ -0,0 +1,279 @@
|
||||
# @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:**
|
||||
```bash
|
||||
# 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
|
||||
|
||||
```mermaid
|
||||
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
|
||||
```typescript
|
||||
// DPoP key generation and signing
|
||||
const publicKey = await this.authRepository.initializeDPoP();
|
||||
const signedProof = await this.securityCore.signDPoPProof('POST', '/auth/login', accessToken);
|
||||
```
|
||||
|
||||
### @core/trust Integration
|
||||
```typescript
|
||||
// Risk assessment for adaptive authentication
|
||||
const { score, signals } = await this.trustRepository.calculateRiskScore();
|
||||
const requiresStepUp = this.shouldRequireStepUp(score, signals);
|
||||
```
|
||||
|
||||
### @core/policy Integration
|
||||
```typescript
|
||||
// Risk-adaptive policy checks
|
||||
const allowed = await this.policyClient.check('login', 'User', {
|
||||
riskScore: 60,
|
||||
deviceSignals: signals
|
||||
});
|
||||
```
|
||||
|
||||
## 5. Policy Enforcement Examples
|
||||
|
||||
**Risk-Adaptive Login:**
|
||||
```typescript
|
||||
// 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:**
|
||||
```typescript
|
||||
// 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
|
||||
```typescript
|
||||
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
|
||||
```typescript
|
||||
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
|
||||
```typescript
|
||||
// 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
|
||||
|
||||
```typescript
|
||||
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
|
||||
|
||||
```typescript
|
||||
// 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
|
||||
```typescript
|
||||
// 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
|
||||
```typescript
|
||||
// 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:**
|
||||
|
||||
1. **"SecurityCore must be initialized"**
|
||||
- Ensure `securityCore.initialize()` is called before auth operations
|
||||
|
||||
2. **"DPoP key generation failed"**
|
||||
- Verify hardware-backed storage is available
|
||||
- Check device security settings (passcode/biometrics enabled)
|
||||
|
||||
3. **"Policy evaluation failed"**
|
||||
- Verify policy bundles are cached locally
|
||||
- Check network connectivity for policy updates
|
||||
|
||||
4. **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
|
||||
Reference in New Issue
Block a user