update-user-roles
Manage user roles in Keycloak by adding or removing client-specific roles for a user within a specified realm. Simplifies role updates for enhanced access control.
Instructions
Add and/or remove client roles for a user in a specific realm and client
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| clientId | Yes | Client ID | |
| realm | Yes | Realm name | |
| rolesToAdd | No | Roles to add | |
| rolesToRemove | No | Roles to remove | |
| userId | Yes | User ID |
Implementation Reference
- src/index.ts:196-280 (handler)Core handler function in KeycloakService class that performs the actual user role updates using Keycloak Admin Client API.async updateUserRoles(params: { realm: string; userId: string; clientId: string; rolesToAdd?: string[]; rolesToRemove?: string[]; }) { await this.authenticate(); this.client.setConfig({ realmName: params.realm }); let added: string[] = []; let removed: string[] = []; let errors: string[] = []; // Find the client let client = null; try { client = await this.client.clients.findOne({ realm: params.realm, id: params.clientId }); } catch {} if (!client) { const clients = await this.client.clients.find({ realm: params.realm }); client = clients.find( (c) => c.clientId === params.clientId || c.id === params.clientId ); } if (!client || !client.id || typeof client.id !== "string") { throw new McpError( ErrorCode.InvalidRequest, `Client '${params.clientId}' not found or invalid in realm '${params.realm}'.` ); } // Fetch all roles for this client const allRoles = await this.client.clients.listRoles({ realm: params.realm, id: client.id, }); const nameToRole = Object.fromEntries(allRoles.map((r) => [r.name, r])); // Add roles if (params.rolesToAdd && params.rolesToAdd.length > 0) { const addObjs = params.rolesToAdd .map((name) => nameToRole[name]) .filter(Boolean); if (addObjs.length !== params.rolesToAdd.length) { errors.push("Some roles to add not found"); } if (addObjs.length > 0) { await this.client.users.addClientRoleMappings({ id: params.userId, realm: params.realm, clientUniqueId: client.id, roles: addObjs, }); added = addObjs.map((r) => r.name!); } } // Remove roles if (params.rolesToRemove && params.rolesToRemove.length > 0) { const removeObjs = params.rolesToRemove .map((name) => nameToRole[name]) .filter(Boolean); if (removeObjs.length !== params.rolesToRemove.length) { errors.push("Some roles to remove not found"); } if (removeObjs.length > 0) { await this.client.users.delClientRoleMappings({ id: params.userId, realm: params.realm, clientUniqueId: client.id, roles: removeObjs, }); removed = removeObjs.map((r) => r.name!); } } return { client, added, removed, errors }; }
- src/index.ts:476-482 (schema)Zod validation schema for update-user-roles tool input parameters.const UpdateUserRolesSchema = z.object({ realm: z.string(), userId: z.string(), clientId: z.string(), rolesToAdd: z.array(z.string()).optional(), rolesToRemove: z.array(z.string()).optional(), });
- src/index.ts:409-423 (registration)Tool registration including name, description, and input schema in the ListToolsRequest handler.{ name: "update-user-roles", description: "Add and/or remove client roles for a user in a specific realm and client", inputSchema: { type: "object", properties: { realm: { type: "string", description: "Realm name" }, userId: { type: "string", description: "User ID" }, clientId: { type: "string", description: "Client ID" }, rolesToAdd: { type: "array", items: { type: "string" }, description: "Roles to add" }, rolesToRemove: { type: "array", items: { type: "string" }, description: "Roles to remove" }, }, required: ["realm", "userId", "clientId"], }, },
- src/index.ts:567-582 (handler)Dispatch handler in the CallToolRequestSchema switch statement that validates input and calls the KeycloakService handler.case "update-user-roles": { const params = UpdateUserRolesSchema.parse(args); const { client, added, removed, errors } = await keycloakService.updateUserRoles(params); return { content: [ { type: "text", text: `Client roles updated for user ${params.userId} in realm ${params.realm} (client: ${ client.clientId }).\nAdded: ${added.join(", ") || "none"}\nRemoved: ${ removed.join(", ") || "none" }${errors.length ? `\nErrors: ${errors.join(", ")}` : ""}`, }, ], }; }