Files
vyndr/src/middleware/auth.js
T
builtbykev 411cb6f196 feat: Feature 2.1 — Parlay Scan with correlation detection + monetization
POST /api/scan/parlay — authenticated parlay analysis:
- Supabase JWT auth middleware (auth.getUser verification)
- 5 correlation types detected between legs (same_game, same_team,
  same_player_conflicting, positive_correlation, blowout_cascade)
- Overall parlay grading (A/B/C/D) with correlation penalty adjustments
- Free tier: 5 scans/month, atomic scan count increment
- Scan 5: full analysis + personalized upgrade pitch
- Scan 6+: 403 block with upgrade pitch
- Pitch personalization from scan history (top stats, grades, tier rec)
- DB writes: picks + scan_sessions per scan

30 new tests, 158 total (131 Node.js + 27 Python), all passing

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 12:45:15 -04:00

33 lines
974 B
JavaScript

const { getSupabaseServiceClient } = require('../utils/supabase');
async function requireAuth(req, res, next) {
const authHeader = req.headers.authorization;
if (!authHeader || !authHeader.startsWith('Bearer ')) {
return res.status(401).json({ error: 'Authentication required' });
}
const token = authHeader.slice(7);
const supabase = getSupabaseServiceClient();
const { data: { user }, error } = await supabase.auth.getUser(token);
if (error || !user) {
return res.status(401).json({ error: 'Invalid or expired token' });
}
// Fetch user profile from our users table
const { data: profile, error: profileError } = await supabase
.from('users')
.select('id, email, tier, scan_count, scan_reset_date, founder_status')
.eq('id', user.id)
.single();
if (profileError || !profile) {
return res.status(401).json({ error: 'User profile not found' });
}
req.user = profile;
next();
}
module.exports = { requireAuth };