equipes keycloak flow

This commit is contained in:
alma 2025-05-03 15:46:14 +02:00
parent 2663d6f23a
commit d2a1d119f4
2 changed files with 84 additions and 52 deletions

View File

@ -13,26 +13,37 @@ export async function GET(
return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
} }
// Safely access the userId parameter // Handle params correctly for Next.js App Router
const userId = String(params?.userId || ''); // Convert to string primitive to avoid "used `params.userId`" error
const userIdParam = params.userId;
const userId = String(userIdParam);
if (!userId) { if (!userId) {
return NextResponse.json({ error: "User ID is required" }, { status: 400 }); return NextResponse.json({ error: "User ID is required" }, { status: 400 });
} }
const kcAdminClient = await getKeycloakAdminClient(); try {
const kcAdminClient = await getKeycloakAdminClient();
// Get all available roles // Get all available roles
const availableRoles = await kcAdminClient.roles.find(); const availableRoles = await kcAdminClient.roles.find();
// Get user's current roles // Get user's current roles
const userRoles = await kcAdminClient.users.listRoleMappings({ const userRoles = await kcAdminClient.users.listRoleMappings({
id: userId, id: userId,
}); });
return NextResponse.json({ return NextResponse.json({
availableRoles, availableRoles,
userRoles, userRoles,
}); });
} catch (keycloakError) {
console.error("Error connecting to Keycloak:", keycloakError);
return NextResponse.json(
{ error: "Failed to connect to Keycloak service", details: String(keycloakError) },
{ status: 503 }
);
}
} catch (error) { } catch (error) {
console.error("Error fetching roles:", error); console.error("Error fetching roles:", error);
return NextResponse.json( return NextResponse.json(
@ -52,51 +63,62 @@ export async function PUT(
return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
} }
// Safely access the userId parameter // Handle params correctly for Next.js App Router
const userId = String(params?.userId || ''); // Convert to string primitive to avoid "used `params.userId`" error
const userIdParam = params.userId;
const userId = String(userIdParam);
if (!userId) { if (!userId) {
return NextResponse.json({ error: "User ID is required" }, { status: 400 }); return NextResponse.json({ error: "User ID is required" }, { status: 400 });
} }
const { roles } = await request.json(); try {
const kcAdminClient = await getKeycloakAdminClient(); const { roles } = await request.json();
const kcAdminClient = await getKeycloakAdminClient();
// Get all available roles // Get all available roles
const availableRoles = await kcAdminClient.roles.find(); const availableRoles = await kcAdminClient.roles.find();
// Get current user roles // Get current user roles
const currentRoles = await kcAdminClient.users.listRoleMappings({ const currentRoles = await kcAdminClient.users.listRoleMappings({
id: userId, id: userId,
}); });
// Find roles to add and remove // Find roles to add and remove
const rolesToAdd = roles.filter( const rolesToAdd = roles.filter(
(role: string) => !currentRoles.realmMappings?.some((r: any) => r.name === role) (role: string) => !currentRoles.realmMappings?.some((r: any) => r.name === role)
); );
const rolesToRemove = currentRoles.realmMappings?.filter( const rolesToRemove = currentRoles.realmMappings?.filter(
(role: any) => !roles.includes(role.name) (role: any) => !roles.includes(role.name)
); );
// Add new roles // Add new roles
for (const roleName of rolesToAdd) { for (const roleName of rolesToAdd) {
const role = availableRoles.find((r: any) => r.name === roleName); const role = availableRoles.find((r: any) => r.name === roleName);
if (role) { if (role) {
await kcAdminClient.users.addRealmRoleMappings({ await kcAdminClient.users.addRealmRoleMappings({
id: userId,
roles: [role as any],
});
}
}
// Remove old roles
if (rolesToRemove && rolesToRemove.length > 0) {
await kcAdminClient.users.delRealmRoleMappings({
id: userId, id: userId,
roles: [role as any], roles: rolesToRemove as any,
}); });
} }
}
// Remove old roles return NextResponse.json({ success: true });
if (rolesToRemove && rolesToRemove.length > 0) { } catch (keycloakError) {
await kcAdminClient.users.delRealmRoleMappings({ console.error("Error connecting to Keycloak:", keycloakError);
id: userId, return NextResponse.json(
roles: rolesToRemove as any, { error: "Failed to connect to Keycloak service", details: String(keycloakError) },
}); { status: 503 }
);
} }
return NextResponse.json({ success: true });
} catch (error) { } catch (error) {
console.error("Error updating roles:", error); console.error("Error updating roles:", error);
return NextResponse.json( return NextResponse.json(

View File

@ -21,11 +21,21 @@ export async function getKeycloakAdminClient(): Promise<KcAdminClient> {
} }
} }
const keycloakUrl = process.env.KEYCLOAK_BASE_URL || process.env.NEXT_PUBLIC_KEYCLOAK_ISSUER || 'http://localhost:8080'; // Only use environment variables - no hardcoded defaults
const adminClientId = process.env.KEYCLOAK_ADMIN_CLIENT_ID || 'admin-cli'; const keycloakUrl = process.env.KEYCLOAK_BASE_URL || process.env.KEYCLOAK_ISSUER || process.env.NEXT_PUBLIC_KEYCLOAK_ISSUER;
const adminUsername = process.env.KEYCLOAK_ADMIN_USERNAME || 'admin'; const adminClientId = process.env.KEYCLOAK_ADMIN_CLIENT_ID;
const adminPassword = process.env.KEYCLOAK_ADMIN_PASSWORD || 'admin'; const adminUsername = process.env.KEYCLOAK_ADMIN_USERNAME;
const realmName = process.env.KEYCLOAK_REALM || 'cercle'; const adminPassword = process.env.KEYCLOAK_ADMIN_PASSWORD;
const realmName = process.env.KEYCLOAK_REALM;
// Validate required environment variables
if (!keycloakUrl) {
throw new Error('Missing Keycloak URL. Please set KEYCLOAK_BASE_URL or KEYCLOAK_ISSUER or NEXT_PUBLIC_KEYCLOAK_ISSUER in your environment variables.');
}
if (!adminClientId || !adminUsername || !adminPassword || !realmName) {
throw new Error('Missing Keycloak admin credentials. Please set KEYCLOAK_ADMIN_CLIENT_ID, KEYCLOAK_ADMIN_USERNAME, KEYCLOAK_ADMIN_PASSWORD, and KEYCLOAK_REALM in your environment variables.');
}
console.log(`Connecting to Keycloak at ${keycloakUrl}, realm: ${realmName}`); console.log(`Connecting to Keycloak at ${keycloakUrl}, realm: ${realmName}`);