chore: migrate user identity from auth0_sub to UUID #219
@@ -58,9 +58,9 @@ const adminGuardPlugin: FastifyPluginAsync = async (fastify) => {
|
||||
|
||||
// Check if user is in admin_users table and not revoked
|
||||
const query = `
|
||||
SELECT auth0_sub, email, role, revoked_at
|
||||
SELECT id, user_profile_id, email, role, revoked_at
|
||||
FROM admin_users
|
||||
WHERE auth0_sub = $1 AND revoked_at IS NULL
|
||||
WHERE user_profile_id = $1 AND revoked_at IS NULL
|
||||
LIMIT 1
|
||||
`;
|
||||
|
||||
|
||||
@@ -121,11 +121,14 @@ const authPlugin: FastifyPluginAsync = async (fastify) => {
|
||||
try {
|
||||
await request.jwtVerify();
|
||||
|
||||
const userId = request.user?.sub;
|
||||
if (!userId) {
|
||||
// Two identifiers: auth0Sub (external, for Auth0 API) and userId (internal UUID, for all DB operations)
|
||||
const auth0Sub = request.user?.sub;
|
||||
if (!auth0Sub) {
|
||||
throw new Error('Missing user ID in JWT');
|
||||
}
|
||||
|
||||
let userId: string = auth0Sub; // Default to auth0Sub; overwritten with UUID after profile load
|
||||
|
||||
// Get or create user profile from database
|
||||
let email = request.user?.email;
|
||||
let displayName: string | undefined;
|
||||
@@ -137,34 +140,35 @@ const authPlugin: FastifyPluginAsync = async (fastify) => {
|
||||
// If JWT doesn't have email, fetch from Auth0 Management API
|
||||
if (!email || email.includes('@unknown.local')) {
|
||||
try {
|
||||
const auth0User = await auth0ManagementClient.getUser(userId);
|
||||
const auth0User = await auth0ManagementClient.getUser(auth0Sub);
|
||||
if (auth0User.email) {
|
||||
email = auth0User.email;
|
||||
emailVerified = auth0User.emailVerified;
|
||||
logger.info('Fetched email from Auth0 Management API', {
|
||||
userId: userId.substring(0, 8) + '...',
|
||||
userId: auth0Sub.substring(0, 8) + '...',
|
||||
hasEmail: true,
|
||||
});
|
||||
}
|
||||
} catch (auth0Error) {
|
||||
logger.warn('Failed to fetch user from Auth0 Management API', {
|
||||
userId: userId.substring(0, 8) + '...',
|
||||
userId: auth0Sub.substring(0, 8) + '...',
|
||||
error: auth0Error instanceof Error ? auth0Error.message : 'Unknown error',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Get or create profile with correct email
|
||||
const profile = await profileRepo.getOrCreate(userId, {
|
||||
email: email || `${userId}@unknown.local`,
|
||||
const profile = await profileRepo.getOrCreate(auth0Sub, {
|
||||
email: email || `${auth0Sub}@unknown.local`,
|
||||
displayName: request.user?.name || request.user?.nickname,
|
||||
});
|
||||
userId = profile.id;
|
||||
|
||||
// If profile has placeholder email but we now have real email, update it
|
||||
if (profile.email.includes('@unknown.local') && email && !email.includes('@unknown.local')) {
|
||||
await profileRepo.updateEmail(userId, email);
|
||||
await profileRepo.updateEmail(auth0Sub, email);
|
||||
logger.info('Updated profile with correct email from Auth0', {
|
||||
userId: userId.substring(0, 8) + '...',
|
||||
userId: auth0Sub.substring(0, 8) + '...',
|
||||
});
|
||||
}
|
||||
|
||||
@@ -178,18 +182,18 @@ const authPlugin: FastifyPluginAsync = async (fastify) => {
|
||||
// Sync email verification status from Auth0 if needed
|
||||
if (!emailVerified) {
|
||||
try {
|
||||
const isVerifiedInAuth0 = await auth0ManagementClient.checkEmailVerified(userId);
|
||||
const isVerifiedInAuth0 = await auth0ManagementClient.checkEmailVerified(auth0Sub);
|
||||
if (isVerifiedInAuth0 && !profile.emailVerified) {
|
||||
await profileRepo.updateEmailVerified(userId, true);
|
||||
await profileRepo.updateEmailVerified(auth0Sub, true);
|
||||
emailVerified = true;
|
||||
logger.info('Synced email verification status from Auth0', {
|
||||
userId: userId.substring(0, 8) + '...',
|
||||
userId: auth0Sub.substring(0, 8) + '...',
|
||||
});
|
||||
}
|
||||
} catch (syncError) {
|
||||
// Don't fail auth if sync fails, just log
|
||||
logger.warn('Failed to sync email verification status', {
|
||||
userId: userId.substring(0, 8) + '...',
|
||||
userId: auth0Sub.substring(0, 8) + '...',
|
||||
error: syncError instanceof Error ? syncError.message : 'Unknown error',
|
||||
});
|
||||
}
|
||||
@@ -197,7 +201,7 @@ const authPlugin: FastifyPluginAsync = async (fastify) => {
|
||||
} catch (profileError) {
|
||||
// Log but don't fail auth if profile fetch fails
|
||||
logger.warn('Failed to fetch user profile', {
|
||||
userId: userId.substring(0, 8) + '...',
|
||||
userId: auth0Sub.substring(0, 8) + '...',
|
||||
error: profileError instanceof Error ? profileError.message : 'Unknown error',
|
||||
});
|
||||
// Fall back to JWT email if available
|
||||
|
||||
Reference in New Issue
Block a user