diff --git a/services/arbiter-3.0/src/routes/auth.js b/services/arbiter-3.0/src/routes/auth.js index 6c514fe..6a391d8 100644 --- a/services/arbiter-3.0/src/routes/auth.js +++ b/services/arbiter-3.0/src/routes/auth.js @@ -2,11 +2,24 @@ const express = require('express'); const passport = require('passport'); const router = express.Router(); +/** + * Standard Discord OAuth - redirects to admin after login + */ router.get('/discord', passport.authenticate('discord')); router.get('/discord/callback', passport.authenticate('discord', { failureRedirect: '/' }), (req, res) => { + // Check if this was a checkout flow (tier stored in session) + if (req.session.pendingCheckoutTier) { + const tierLevel = req.session.pendingCheckoutTier; + delete req.session.pendingCheckoutTier; // Clean up + + // Redirect to checkout creation with Discord ID now available + return res.redirect(`/stripe/checkout?tier=${tierLevel}`); + } + + // Standard admin redirect res.redirect('/admin'); }); diff --git a/services/arbiter-3.0/src/routes/stripe.js b/services/arbiter-3.0/src/routes/stripe.js index eca2ac2..45f3118 100644 --- a/services/arbiter-3.0/src/routes/stripe.js +++ b/services/arbiter-3.0/src/routes/stripe.js @@ -3,6 +3,7 @@ * Handles checkout sessions, webhooks, and customer portal * Date: April 3, 2026 * Updated: April 6, 2026 - Added Discord role sync (Task #87) + * Updated: April 10, 2026 - Added /auth and /checkout routes for Discord OAuth flow */ const express = require('express'); @@ -27,9 +28,96 @@ const corsOptions = { router.options('/create-checkout-session', cors(corsOptions)); /** - * CREATE CHECKOUT SESSION + * STRIPE AUTH - Entry point from website + * GET /stripe/auth?tier=X + * Stores tier in session, redirects to Discord OAuth + */ +router.get('/auth', (req, res) => { + const tierLevel = req.query.tier; + + if (!tierLevel || isNaN(parseInt(tierLevel))) { + return res.status(400).send('Invalid tier level. Please return to the subscribe page and try again.'); + } + + // Store tier in session for after OAuth callback + req.session.pendingCheckoutTier = parseInt(tierLevel); + + // Redirect to Discord OAuth + res.redirect('/auth/discord'); +}); + +/** + * CHECKOUT - Creates Stripe session after Discord OAuth + * GET /stripe/checkout?tier=X + * Called from auth callback, user is now logged in + */ +router.get('/checkout', async (req, res) => { + try { + // User must be authenticated + if (!req.user || !req.user.id) { + return res.redirect('/stripe/auth?tier=' + (req.query.tier || '1')); + } + + const tierLevel = parseInt(req.query.tier); + const discordId = req.user.id; + + if (!tierLevel || isNaN(tierLevel)) { + return res.status(400).send('Invalid tier level'); + } + + // Get Stripe Price ID from database + const productResult = await db.query( + 'SELECT stripe_price_id, tier_name, billing_type FROM stripe_products WHERE tier_level = $1', + [tierLevel] + ); + + if (productResult.rows.length === 0) { + return res.status(404).send('Invalid tier level - product not found'); + } + + const product = productResult.rows[0]; + const priceId = product.stripe_price_id; + const billingMode = product.billing_type === 'one-time' ? 'payment' : 'subscription'; + + console.log('🔍 Creating checkout session (OAuth flow):', { + discord_id: discordId, + tier_level: tierLevel, + tier_name: product.tier_name, + priceId, + billingMode + }); + + // Create Stripe Checkout Session WITH client_reference_id + const sessionConfig = { + payment_method_types: ['card'], + line_items: [{ price: priceId, quantity: 1 }], + mode: billingMode, + client_reference_id: discordId, // 🔑 THE KEY - Discord ID for webhook + success_url: 'https://firefrostgaming.com/success', + cancel_url: 'https://firefrostgaming.com/subscribe', + metadata: { + tier_level: tierLevel.toString(), + tier_name: product.tier_name, + discord_id: discordId + } + }; + + const session = await stripe.checkout.sessions.create(sessionConfig); + + // Redirect directly to Stripe Checkout + res.redirect(session.url); + + } catch (error) { + console.error('Checkout creation error:', error); + res.status(500).send('Failed to create checkout session. Please try again.'); + } +}); + +/** + * CREATE CHECKOUT SESSION (Legacy API - kept for compatibility) * POST /stripe/create-checkout-session * Body: { tier_level } + * NOTE: This doesn't have Discord ID - use /stripe/auth flow instead */ router.post('/create-checkout-session', cors(corsOptions), async (req, res) => { try { @@ -53,7 +141,7 @@ router.post('/create-checkout-session', cors(corsOptions), async (req, res) => { const priceId = product.stripe_price_id; const billingMode = product.billing_type === 'one-time' ? 'payment' : 'subscription'; - console.log('🔍 Creating checkout session:', { + console.log('🔍 Creating checkout session (legacy, no Discord ID):', { tier_level, tier_name: product.tier_name, priceId,