The Backstory
While building a module in NestJS, I encountered a common dilemma: How to secure sensitive data in populated documents without overhauling our existing architecture?
Here’s how I addressed it pragmatically, while acknowledging room for improvement.
The Problem, Simplified
- Combined Auth/Profile Models: User authentication and profile data lived in a single schema (a known anti-pattern, but we all cut corners sometimes 😬).
- Leaky Projections: Sensitive fields like password and OTP slipped into API responses through populated relationships.
- Repetitive Code: Similar field exclusions were duplicated across multiple queries.
The Middle-Ground Solution
Instead of fully refactoring our auth system (which would’ve been ideal), I focused on immediate risk mitigation:
Step 1: Centralized Projection Configs
// database/projections.config.ts export const UserSafeProjection = { password: 0, otp: 0, email: 0, mobileNumber: 0, __v: 0 }; export const EntityBaseProjection = { __v: 0 };
Step 2: Reusable Population Blueprints
// database/populations.config.ts export const TrainingMaterialPopulations = [ { path: 'createdBy', select: UserSafeProjection }, { path: 'project', populate: { path: 'organisation', select: EntityBaseProjection } } ];
Step 3: Cleaner Service Implementation
async findById(id: string) { return this.trainingMaterialModel .findById(id) .populate(TrainingMaterialPopulations) .select(EntityBaseProjection) .lean(); }
Why This Works (For Now)
Pros | Cons |
---|---|
Immediate security improvement | Still need proper auth separation |
Reduces code duplication | Partial technical debt remains |
Easy to maintain/update | Projections ≠ full authorization |
Lessons Learned
- Layer Your Security: Projections are just one piece of the puzzle.
- Document Tradeoffs: Added JSDoc:
// TEMP: Remove after auth refactor (Q4?)
- Start Small: Even partial solutions can reduce risk while you plan bigger fixes.
Next Steps (If I Weren’t Lazy)
- Separate auth into its own service/collection.
- Implement proper role-based access control.
- Add encryption for sensitive fields.
Your Thoughts?
How do you balance immediate fixes with long-term ideals? Have a better pattern for handling nested projections? Let’s discuss!
Top comments (0)