Latest code
This commit is contained in:
parent
145566ad7d
commit
da921f870a
|
|
@ -1188,16 +1188,27 @@ router.post(
|
||||||
// Endpoint for other services (like BuySellService) to validate JWT tokens
|
// Endpoint for other services (like BuySellService) to validate JWT tokens
|
||||||
// This allows centralized token validation
|
// This allows centralized token validation
|
||||||
router.post('/validate-token', async (req, res) => {
|
router.post('/validate-token', async (req, res) => {
|
||||||
|
const clientIp = req.ip || req.headers['x-forwarded-for']?.split(',')[0]?.trim() || req.headers['x-real-ip'] || 'unknown';
|
||||||
|
const userAgent = req.headers['user-agent'] || 'unknown';
|
||||||
|
|
||||||
|
console.log(`[Auth Service] POST /auth/validate-token - Request received`);
|
||||||
|
console.log(`[Auth Service] Client IP: ${clientIp}`);
|
||||||
|
console.log(`[Auth Service] User-Agent: ${userAgent.substring(0, 80)}`);
|
||||||
|
console.log(`[Auth Service] Request body contains token: ${!!req.body?.token}`);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { token } = req.body;
|
const { token } = req.body;
|
||||||
|
|
||||||
if (!token) {
|
if (!token) {
|
||||||
|
console.log(`[Auth Service] ❌ FAILED: Token is missing in request body`);
|
||||||
return res.status(400).json({
|
return res.status(400).json({
|
||||||
valid: false,
|
valid: false,
|
||||||
error: 'Token is required'
|
error: 'Token is required'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log(`[Auth Service] Token received (length: ${token.length} characters)`);
|
||||||
|
|
||||||
// Use the auth middleware logic to validate token
|
// Use the auth middleware logic to validate token
|
||||||
const jwt = require('jsonwebtoken');
|
const jwt = require('jsonwebtoken');
|
||||||
const { getKeySecret, getAllKeys, validateTokenClaims } = require('../services/jwtKeys');
|
const { getKeySecret, getAllKeys, validateTokenClaims } = require('../services/jwtKeys');
|
||||||
|
|
@ -1208,9 +1219,17 @@ router.post('/validate-token', async (req, res) => {
|
||||||
try {
|
try {
|
||||||
decoded = jwt.decode(token, { complete: true });
|
decoded = jwt.decode(token, { complete: true });
|
||||||
if (!decoded || !decoded.header) {
|
if (!decoded || !decoded.header) {
|
||||||
|
console.log(`[Auth Service] ❌ FAILED: Invalid token format - unable to decode header`);
|
||||||
return res.json({ valid: false, error: 'Invalid token format' });
|
return res.json({ valid: false, error: 'Invalid token format' });
|
||||||
}
|
}
|
||||||
|
console.log(`[Auth Service] Token decoded successfully`);
|
||||||
|
console.log(`[Auth Service] Token header:`, {
|
||||||
|
alg: decoded.header.alg,
|
||||||
|
kid: decoded.header.kid || 'NOT SET',
|
||||||
|
typ: decoded.header.typ,
|
||||||
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
console.log(`[Auth Service] ❌ FAILED: Error decoding token - ${err.message}`);
|
||||||
return res.json({ valid: false, error: 'Invalid token' });
|
return res.json({ valid: false, error: 'Invalid token' });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1218,44 +1237,75 @@ router.post('/validate-token', async (req, res) => {
|
||||||
const keyId = decoded.header.kid;
|
const keyId = decoded.header.kid;
|
||||||
let payload = null;
|
let payload = null;
|
||||||
let verified = false;
|
let verified = false;
|
||||||
|
let verificationMethod = null;
|
||||||
|
|
||||||
if (keyId) {
|
if (keyId) {
|
||||||
|
console.log(`[Auth Service] Key ID found in token: ${keyId}`);
|
||||||
const secret = getKeySecret(keyId);
|
const secret = getKeySecret(keyId);
|
||||||
if (secret) {
|
if (secret) {
|
||||||
|
console.log(`[Auth Service] Attempting verification with key ID: ${keyId}`);
|
||||||
try {
|
try {
|
||||||
payload = jwt.verify(token, secret);
|
payload = jwt.verify(token, secret);
|
||||||
verified = true;
|
verified = true;
|
||||||
|
verificationMethod = `keyId: ${keyId}`;
|
||||||
|
console.log(`[Auth Service] ✅ Token verified successfully using key ID: ${keyId}`);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
console.log(`[Auth Service] ❌ Verification failed with key ID ${keyId}: ${err.message}`);
|
||||||
return res.json({ valid: false, error: 'Invalid or expired token' });
|
return res.json({ valid: false, error: 'Invalid or expired token' });
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
console.log(`[Auth Service] ⚠️ Key ID ${keyId} not found in available keys, will try all keys`);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
console.log(`[Auth Service] ⚠️ No key ID in token header, trying all available keys`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If key ID not found or not specified, try all keys (for rotation support)
|
// If key ID not found or not specified, try all keys (for rotation support)
|
||||||
if (!verified) {
|
if (!verified) {
|
||||||
const allKeys = getAllKeys();
|
const allKeys = getAllKeys();
|
||||||
|
console.log(`[Auth Service] Attempting verification with ${Object.keys(allKeys).length} available keys`);
|
||||||
for (const [kid, keySecret] of Object.entries(allKeys)) {
|
for (const [kid, keySecret] of Object.entries(allKeys)) {
|
||||||
try {
|
try {
|
||||||
payload = jwt.verify(token, keySecret);
|
payload = jwt.verify(token, keySecret);
|
||||||
verified = true;
|
verified = true;
|
||||||
|
verificationMethod = `allKeys: ${kid}`;
|
||||||
|
console.log(`[Auth Service] ✅ Token verified successfully using key: ${kid}`);
|
||||||
break;
|
break;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
// Try next key silently
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!verified) {
|
||||||
|
console.log(`[Auth Service] ❌ FAILED: Token verification failed with all available keys`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!verified || !payload) {
|
if (!verified || !payload) {
|
||||||
|
console.log(`[Auth Service] ❌ FINAL RESULT: Token is invalid or expired`);
|
||||||
return res.json({ valid: false, error: 'Invalid or expired token' });
|
return res.json({ valid: false, error: 'Invalid or expired token' });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log(`[Auth Service] Token payload extracted:`, {
|
||||||
|
userId: payload.sub,
|
||||||
|
role: payload.role,
|
||||||
|
userType: payload.user_type,
|
||||||
|
exp: payload.exp ? new Date(payload.exp * 1000).toISOString() : 'NOT SET',
|
||||||
|
iat: payload.iat ? new Date(payload.iat * 1000).toISOString() : 'NOT SET',
|
||||||
|
tokenVersion: payload.token_version || 1,
|
||||||
|
});
|
||||||
|
|
||||||
// Validate JWT claims (iss, aud, exp, iat, nbf)
|
// Validate JWT claims (iss, aud, exp, iat, nbf)
|
||||||
|
console.log(`[Auth Service] Validating JWT claims...`);
|
||||||
const claimsValidation = validateTokenClaims(payload);
|
const claimsValidation = validateTokenClaims(payload);
|
||||||
if (!claimsValidation.valid) {
|
if (!claimsValidation.valid) {
|
||||||
|
console.log(`[Auth Service] ❌ FAILED: Claims validation failed - ${claimsValidation.reason}`);
|
||||||
return res.json({ valid: false, error: 'Invalid token claims' });
|
return res.json({ valid: false, error: 'Invalid token claims' });
|
||||||
}
|
}
|
||||||
|
console.log(`[Auth Service] ✅ Claims validation passed`);
|
||||||
|
|
||||||
// Validate token_version to ensure token hasn't been invalidated by logout-all-devices
|
// Validate token_version to ensure token hasn't been invalidated by logout-all-devices
|
||||||
|
console.log(`[Auth Service] Checking token version in database for user: ${payload.sub}`);
|
||||||
try {
|
try {
|
||||||
const { rows } = await db.query(
|
const { rows } = await db.query(
|
||||||
`SELECT COALESCE(token_version, 1) as token_version FROM users WHERE id = $1`,
|
`SELECT COALESCE(token_version, 1) as token_version FROM users WHERE id = $1`,
|
||||||
|
|
@ -1263,28 +1313,45 @@ router.post('/validate-token', async (req, res) => {
|
||||||
);
|
);
|
||||||
|
|
||||||
if (rows.length === 0) {
|
if (rows.length === 0) {
|
||||||
|
console.log(`[Auth Service] ❌ FAILED: User not found in database: ${payload.sub}`);
|
||||||
return res.json({ valid: false, error: 'User not found' });
|
return res.json({ valid: false, error: 'User not found' });
|
||||||
}
|
}
|
||||||
|
|
||||||
const userTokenVersion = rows[0].token_version;
|
const userTokenVersion = rows[0].token_version;
|
||||||
const tokenVersion = payload.token_version || 1;
|
const tokenVersion = payload.token_version || 1;
|
||||||
|
|
||||||
|
console.log(`[Auth Service] Token version check:`, {
|
||||||
|
tokenVersion,
|
||||||
|
userTokenVersion,
|
||||||
|
match: tokenVersion === userTokenVersion,
|
||||||
|
});
|
||||||
|
|
||||||
// If token version doesn't match, token has been invalidated
|
// If token version doesn't match, token has been invalidated
|
||||||
if (tokenVersion !== userTokenVersion) {
|
if (tokenVersion !== userTokenVersion) {
|
||||||
|
console.log(`[Auth Service] ❌ FAILED: Token version mismatch - token has been invalidated`);
|
||||||
return res.json({ valid: false, error: 'Token has been invalidated' });
|
return res.json({ valid: false, error: 'Token has been invalidated' });
|
||||||
}
|
}
|
||||||
|
console.log(`[Auth Service] ✅ Token version check passed`);
|
||||||
} catch (dbErr) {
|
} catch (dbErr) {
|
||||||
// Handle missing token_version column gracefully
|
// Handle missing token_version column gracefully
|
||||||
if (dbErr.code === '42703' && dbErr.message && dbErr.message.includes('token_version')) {
|
if (dbErr.code === '42703' && dbErr.message && dbErr.message.includes('token_version')) {
|
||||||
console.warn('token_version column not found in database, skipping version check');
|
console.warn('[Auth Service] ⚠️ token_version column not found in database, skipping version check');
|
||||||
// Continue without token version validation
|
// Continue without token version validation
|
||||||
} else {
|
} else {
|
||||||
console.error('Error validating token version:', dbErr);
|
console.error('[Auth Service] ❌ Error validating token version:', dbErr);
|
||||||
return res.status(500).json({ valid: false, error: 'Internal server error' });
|
return res.status(500).json({ valid: false, error: 'Internal server error' });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Token is valid - return user info
|
// Token is valid - return user info
|
||||||
|
console.log(`[Auth Service] ✅ FINAL RESULT: Token is VALID`);
|
||||||
|
console.log(`[Auth Service] Returning user info:`, {
|
||||||
|
userId: payload.sub,
|
||||||
|
role: payload.role,
|
||||||
|
userType: payload.user_type,
|
||||||
|
verificationMethod,
|
||||||
|
});
|
||||||
|
|
||||||
return res.json({
|
return res.json({
|
||||||
valid: true,
|
valid: true,
|
||||||
payload: {
|
payload: {
|
||||||
|
|
@ -1297,7 +1364,8 @@ router.post('/validate-token', async (req, res) => {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('validate-token error:', err);
|
console.error('[Auth Service] ❌ UNEXPECTED ERROR in validate-token:', err);
|
||||||
|
console.error('[Auth Service] Error stack:', err.stack);
|
||||||
return res.status(500).json({ valid: false, error: 'Internal server error' });
|
return res.status(500).json({ valid: false, error: 'Internal server error' });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue