Improve user ID generation for consistent authentication

Implement deterministic UUID generation using SHA256 hashing for Replit user IDs to ensure consistent user identification across sessions and database operations.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 170e18f0-0f13-4eca-8643-546bba1dd8cc
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/8cc42625-c1f5-4e43-99bd-77f2c4dedee2/170e18f0-0f13-4eca-8643-546bba1dd8cc/vqbrWR9
This commit is contained in:
sebastjanartic 2025-09-02 12:47:24 +00:00
parent 68bb99739b
commit d91a94675c
3 changed files with 40 additions and 6 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

View File

@ -6,6 +6,7 @@ import type { Express, RequestHandler } from "express";
import memoize from "memoizee";
import connectPg from "connect-pg-simple";
import { storage } from "./storage";
import { createHash } from "crypto";
if (!process.env.REPLIT_DOMAINS) {
throw new Error("Environment variable REPLIT_DOMAINS not provided");
@ -53,9 +54,23 @@ function updateUserSession(
user.expires_at = user.claims?.exp;
}
function generateDeterministicUUID(replitId: string): string {
// Create a deterministic UUID from Replit ID
// This ensures the same Replit user always gets the same UUID
const hash = createHash('sha256').update(`replit_${replitId}`).digest('hex');
// Format as UUID v4: xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
return [
hash.substring(0, 8),
hash.substring(8, 12),
'4' + hash.substring(13, 16),
(parseInt(hash.substring(16, 17), 16) & 0x3 | 0x8).toString(16) + hash.substring(17, 20),
hash.substring(20, 32)
].join('-');
}
async function upsertUser(claims: any) {
// Convert Replit numeric ID to string format compatible with our schema
const userId = `replit_${claims["sub"]}`;
// Generate a deterministic UUID from Replit ID
const userId = generateDeterministicUUID(claims["sub"]);
await storage.upsertUser({
id: userId,
@ -163,8 +178,8 @@ export const isAdmin: RequestHandler = async (req, res, next) => {
}
try {
// Convert Replit numeric ID to our internal format
const userId = `replit_${user.claims.sub}`;
// Generate the same deterministic UUID from Replit ID
const userId = generateDeterministicUUID(user.claims.sub);
const dbUser = await storage.getUser(userId);
if (!dbUser || !dbUser.isAdmin) {
return res.status(403).json({ message: "Admin access required" });

View File

@ -860,9 +860,28 @@ export async function registerRoutes(app: Express): Promise<Server> {
// Auth route to get current user
app.get('/api/auth/user', isAuthenticated, async (req: any, res) => {
try {
const userId = `replit_${req.user.claims.sub}`;
// Import the generateDeterministicUUID function from replitAuth
const { createHash } = await import('crypto');
function generateDeterministicUUID(replitId: string): string {
const hash = createHash('sha256').update(`replit_${replitId}`).digest('hex');
return [
hash.substring(0, 8),
hash.substring(8, 12),
'4' + hash.substring(13, 16),
(parseInt(hash.substring(16, 17), 16) & 0x3 | 0x8).toString(16) + hash.substring(17, 20),
hash.substring(20, 32)
].join('-');
}
const userId = generateDeterministicUUID(req.user.claims.sub);
const user = await storage.getUser(userId);
res.json(user);
if (!user) {
return res.status(404).json({ message: "User not found" });
}
// Remove sensitive data
const { passwordHash, ...userResponse } = user;
res.json(userResponse);
} catch (error) {
console.error("Error fetching user:", error);
res.status(500).json({ message: "Failed to fetch user" });