const { PrismaClient } = require('@prisma/client'); const bcrypt = require('bcryptjs'); require('dotenv').config(); const prisma = new PrismaClient(); async function syncUsers() { try { console.log('Starting user sync process...'); // Use your existing /api/users endpoint to get users from Keycloak // This endpoint already exists in your codebase and handles all the Keycloak auth const apiUrl = process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000'; console.log(`Fetching users from: ${apiUrl}/api/users`); // Get client credentials token for authentication const tokenResponse = await fetch( `${process.env.KEYCLOAK_BASE_URL}/realms/${process.env.KEYCLOAK_REALM}/protocol/openid-connect/token`, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, body: new URLSearchParams({ grant_type: 'client_credentials', client_id: process.env.KEYCLOAK_CLIENT_ID, client_secret: process.env.KEYCLOAK_CLIENT_SECRET, }), } ); const tokenData = await tokenResponse.json(); if (!tokenResponse.ok) { throw new Error(`Failed to get token: ${JSON.stringify(tokenData)}`); } console.log("Token obtained successfully"); // Now fetch users from Keycloak const usersResponse = await fetch( `${process.env.KEYCLOAK_BASE_URL}/admin/realms/${process.env.KEYCLOAK_REALM}/users?briefRepresentation=false`, { headers: { Authorization: `Bearer ${tokenData.access_token}`, 'Content-Type': 'application/json', }, } ); if (!usersResponse.ok) { throw new Error(`Failed to fetch users: ${usersResponse.status}`); } const users = await usersResponse.json(); // Filter out service accounts and users from other realms const filteredUsers = users.filter((user) => !user.serviceAccountClientId && // Remove service accounts (!user.realm || user.realm === process.env.KEYCLOAK_REALM) // Only users from our realm ); console.log(`Fetched ${filteredUsers.length} users from Keycloak API`); const results = { total: filteredUsers.length, created: 0, updated: 0, failed: 0, }; // Process each user from Keycloak for (const user of filteredUsers) { try { // Check if the keycloak ID exists in our database const existingUser = await prisma.user.findUnique({ where: { id: user.id }, }); if (existingUser) { // Update existing user await prisma.user.update({ where: { id: user.id }, data: { email: user.email, // Don't update password as it might be locally changed updatedAt: new Date(), }, }); console.log(`Updated user: ${user.id} (${user.email})`); results.updated++; } else { // Create new user // Generate a temporary random password const tempPassword = await bcrypt.hash(Math.random().toString(36).slice(-10), 10); await prisma.user.create({ data: { id: user.id, // Use the keycloak ID as our primary ID email: user.email, password: tempPassword, createdAt: new Date(), updatedAt: new Date(), }, }); console.log(`Created new user: ${user.id} (${user.email})`); results.created++; } } catch (error) { console.error(`Error processing user ${user.id}:`, error); results.failed++; } } console.log('Sync completed. Results:', results); } catch (error) { console.error('Error syncing users:', error); } finally { await prisma.$disconnect(); } } // Run the sync function syncUsers();