How to securely implement dynamic QR Code redirection with expiration in Node.js and MongoDB?
I’m building a SaaS similar to dynamic QR Code platforms (e.g. Code2Scan), where users create a short URL that points to a final destination (landing page, WhatsApp link, event page, etc.).
The flow I’m trying to implement in Node.js + Express + MongoDB is:
1. User creates a “dynamic QR Code”:
- I generate a short URL like: `https://example.com/r/abc123%5C%60
- I save metadata in MongoDB with:
- `targetUrl` (final destination, must be HTTPS)
- `expiresAt` (date when the redirect stops working)
- `createdAt`
- `status` (active / expired / blocked)
- maybe some tracking fields like `scanCount`, `lastScanAt`
2. When someone scans the QR code:
- They hit `GET /r/:slug`
- I look up `slug` in MongoDB
- If it’s valid and not expired, I redirect to `targetUrl`
- If it’s expired or blocked, I want to show a custom page instead of redirecting
What I’m unsure about is the best architecture and patterns for:
- Enforcing HTTPS-only `targetUrl` (avoid http and unsafe URLs).
- Preventing open redirect / unsafe redirect issues (e.g. someone saving a malicious URL).
- Handling expiration efficiently:
- Is it better to check `expiresAt` on every request,
- or run a background job to mark documents as expired?
- Designing the MongoDB schema and indexes for this use case.
- A clean way to log scans (IP, user-agent, datetime) without slowing down the redirect too much.
Currently I have something like this (simplified):
// Schema (Mongoose)
const DynamicLinkSchema = new mongoose.Schema({
slug: { type: String, unique: true, index: true },
targetUrl: String,
status: { type: String, default: 'active' }, // 'active', 'expired', 'blocked'
createdAt: { type: Date, default: Date.now },
expiresAt: Date,
scanCount: { type: Number, default: 0 },
lastScanAt: Date
});
// Route
app.get('/r/:slug', async (req, res) => {
const { slug } = req.params;
const link = await DynamicLink.findOne({ slug });
if (!link) {
return res.status(404).send('Not found');
}
// TODO: validate HTTPS, expiration, logging, etc.
return res.redirect(link.targetUrl);
});
Questions:
1. How would you improve this schema for a dynamic QR Code / short URL service with expiration?
2. What is the best practice to validate `targetUrl` (HTTPS only, and avoid open redirect vulnerabilities)?
3. Is there a recommended way to handle expiration (only by checking `expiresAt` on each request, or also with a background job/TTL index)?
4. How can I log scans in a performant way without blocking the redirect?
Any patterns, examples, or best practices for this kind of URL redirection service would be very helpful.