EverydayTech Platform - Developer Reference
Complete Source Code Documentation - All Applications
Loading...
Searching...
No Matches
customerAuth.js
Go to the documentation of this file.
1const jwt = require('jsonwebtoken');
2const pool = require('../services/db');
3
4/**
5 * Authenticate customer user via JWT token
6 * Sets req.customerUserId, req.customerId, req.tenantId
7 * Customer tokens are separate from admin tokens
8 */
9async function authenticateCustomer(req, res, next) {
10 try {
11 const authHeader = req.headers['authorization'];
12 const token = authHeader && authHeader.split(' ')[1]; // Bearer TOKEN
13
14 if (!token) {
15 return res.status(401).json({ error: 'Access denied. No token provided.' });
16 }
17
18 // Verify token
19 const decoded = jwt.verify(token, process.env.JWT_SECRET);
20
21 // Validate token type
22 if (decoded.type !== 'customer') {
23 return res.status(403).json({ error: 'Invalid token type. Customer token required.' });
24 }
25
26 // Check if session exists and is valid
27 const sessionResult = await pool.query(
28 `SELECT cs.*, cu.customer_id, cu.tenant_id, cu.is_active
29 FROM customer_sessions cs
30 JOIN customer_users cu ON cs.customer_user_id = cu.customer_user_id
31 WHERE cs.customer_user_id = $1
32 AND cs.expires_at > NOW()`,
33 [decoded.customerUserId]
34 );
35
36 if (sessionResult.rows.length === 0) {
37 return res.status(401).json({ error: 'Session expired or invalid.' });
38 }
39
40 const session = sessionResult.rows[0];
41
42 // Check if user is active
43 if (!session.is_active) {
44 return res.status(403).json({ error: 'Account is deactivated.' });
45 }
46
47 // Set request properties
48 req.customerUserId = decoded.customerUserId;
49 req.customerId = session.customer_id;
50 req.tenantId = session.tenant_id;
51
52 next();
53 } catch (error) {
54 console.error('Customer authentication error:', error);
55
56 if (error.name === 'JsonWebTokenError') {
57 return res.status(401).json({ error: 'Invalid token.' });
58 }
59 if (error.name === 'TokenExpiredError') {
60 return res.status(401).json({ error: 'Token expired.' });
61 }
62
63 return res.status(500).json({ error: 'Authentication failed.', details: error.message });
64 }
65}
66
67/**
68 * Set customer context middleware
69 * Ensures customer can only access their own data
70 * Validates that customerId in request matches authenticated customer
71 */
72function setCustomerContext(req, res, next) {
73 // Customer context is already set by authenticateCustomer
74 // This middleware validates that customer is accessing their own data
75
76 // If a customer_id is in the URL params or body, validate it matches
77 const requestedCustomerId = parseInt(req.params.customer_id || req.body.customer_id);
78
79 if (requestedCustomerId && requestedCustomerId !== req.customerId) {
80 return res.status(403).json({
81 error: 'Access denied. You can only access your own data.'
82 });
83 }
84
85 next();
86}
87
88/**
89 * Log customer audit event
90 * Call this after successful actions to track customer activity
91 */
92async function logCustomerAudit(customerUserId, tenantId, action, entityType, entityId, details, ipAddress) {
93 try {
94 await pool.query(
95 `INSERT INTO customer_audit_log
96 (tenant_id, customer_user_id, action, entity_type, entity_id, details, ip_address)
97 VALUES ($1, $2, $3, $4, $5, $6, $7)`,
98 [tenantId, customerUserId, action, entityType, entityId, details, ipAddress]
99 );
100 } catch (error) {
101 console.error('Error logging customer audit:', error);
102 // Don't throw - audit log failures shouldn't break requests
103 }
104}
105
106module.exports = {
107 authenticateCustomer,
108 setCustomerContext,
109 logCustomerAudit
110};