feat: add keycloak and postgres

This commit is contained in:
Masaki Yatsu
2025-08-15 11:21:54 +09:00
parent 81016267af
commit ed1ba74797
20 changed files with 1656 additions and 0 deletions

View File

@@ -0,0 +1,70 @@
import KcAdminClient from "@keycloak/keycloak-admin-client";
import invariant from "tiny-invariant";
const main = async () => {
const keycloakHost = process.env.KEYCLOAK_HOST;
invariant(keycloakHost, "KEYCLOAK_HOST environment variable is required.");
const adminUsername = process.env.KEYCLOAK_ADMIN_USER;
invariant(adminUsername, "KEYCLOAK_ADMIN_USER environment variable is required.");
const adminPassword = process.env.KEYCLOAK_ADMIN_PASSWORD;
invariant(adminPassword, "KEYCLOAK_ADMIN_PASSWORD environment variable is required");
const realmName = process.env.KEYCLOAK_REALM;
invariant(realmName, "KEYCLOAK_REALM environment variable is required");
const clientId = process.env.KEYCLOAK_CLIENT_ID;
invariant(clientId, "KEYCLOAK_CLIENT_ID environment variable is required");
const kcAdminClient = new KcAdminClient({
baseUrl: `https://${keycloakHost}`,
realmName: "master",
});
try {
await kcAdminClient.auth({
username: adminUsername,
password: adminPassword,
grantType: "password",
clientId: "admin-cli",
});
console.log("Authentication successful.");
kcAdminClient.setConfig({ realmName });
const clients = await kcAdminClient.clients.find({ clientId });
if (clients.length === 0) {
throw new Error(`Client '${clientId}' not found.`);
}
const client = clients[0];
invariant(client.id, "Client ID is not set");
const mapperName = `aud-mapper-${clientId}`;
const audienceMapper = {
name: mapperName,
protocol: "openid-connect",
protocolMapper: "oidc-audience-mapper",
config: {
"included.client.audience": clientId,
"id.token.claim": "true",
"access.token.claim": "true",
},
};
const existingMappers = await kcAdminClient.clients.listProtocolMappers({ id: client.id });
if (existingMappers.some((mapper) => mapper.name === mapperName)) {
console.warn(`Audience Mapper '${mapperName}' already exists for the client.`);
} else {
await kcAdminClient.clients.addProtocolMapper({ id: client.id }, audienceMapper);
console.log(`Audience Mapper '${mapperName}' added directly to the client.`);
}
} catch (error) {
console.error("An error occurred:", error);
// eslint-disable-next-line unicorn/no-process-exit
process.exit(1);
}
};
main();

View File

@@ -0,0 +1,121 @@
import KcAdminClient from "@keycloak/keycloak-admin-client";
import invariant from "tiny-invariant";
const main = async () => {
const keycloakHost = process.env.KEYCLOAK_HOST;
invariant(keycloakHost, "KEYCLOAK_HOST environment variable is required.");
const adminUsername = process.env.KEYCLOAK_ADMIN_USER;
invariant(adminUsername, "KEYCLOAK_ADMIN_USER environment variable is required.");
const adminPassword = process.env.KEYCLOAK_ADMIN_PASSWORD;
invariant(adminPassword, "KEYCLOAK_ADMIN_PASSWORD environment variable is required");
const realmName = process.env.KEYCLOAK_REALM;
invariant(realmName, "KEYCLOAK_REALM environment variable is required");
const minioClientId = process.env.MINIO_OIDC_CLIENT_ID;
invariant(minioClientId, "MINIO_OIDC_CLIENT_ID environment variable is required");
const policyValue = process.env.MINIO_POLICY || "readwrite";
console.log(`Setting minioPolicy attribute with value: ${policyValue}`);
const kcAdminClient = new KcAdminClient({
baseUrl: `https://${keycloakHost}`,
realmName: "master",
});
try {
await kcAdminClient.auth({
username: adminUsername,
password: adminPassword,
grantType: "password",
clientId: "admin-cli",
});
console.log("Authentication successful.");
// Set realm to work with
kcAdminClient.setConfig({
realmName,
});
// Get current User Profile configuration
const userProfile = await kcAdminClient.users.getProfile();
// Check if minioPolicy attribute already exists
const existingAttribute = userProfile.attributes?.find(
(attr: any) => attr.name === "minioPolicy"
);
if (existingAttribute) {
console.log("minioPolicy attribute already exists in User Profile.");
} else {
// Add minioPolicy attribute to User Profile with proper permissions
if (!userProfile.attributes) {
userProfile.attributes = [];
}
userProfile.attributes.push({
name: "minioPolicy",
displayName: "MinIO Policy",
permissions: {
view: ["admin", "user"],
edit: ["admin"],
},
validations: {
options: { options: ["readwrite", "readonly", "writeonly"] },
},
});
// Update User Profile
await kcAdminClient.users.updateProfile(userProfile);
console.log(
"minioPolicy attribute added to User Profile successfully with admin edit permissions."
);
}
// Create protocol mapper for the minioPolicy attribute if it doesn't exist
const minioClient = await kcAdminClient.clients.find({ clientId: minioClientId });
if (minioClient.length === 0) {
console.error(`Client '${minioClientId}' not found.`);
// eslint-disable-next-line unicorn/no-process-exit
process.exit(1);
}
const clientId = minioClient[0].id;
invariant(clientId, "Client ID is required");
// Check if the mapper already exists
const mappers = await kcAdminClient.clients.listProtocolMappers({ id: clientId });
const existingMapper = mappers.find((mapper) => mapper.name === "MinIO Policy");
if (existingMapper) {
console.log("MinIO Policy mapper already exists.");
} else {
// Create the protocol mapper
await kcAdminClient.clients.addProtocolMapper(
{ id: clientId },
{
name: "MinIO Policy",
protocol: "openid-connect",
protocolMapper: "oidc-usermodel-attribute-mapper",
config: {
"userinfo.token.claim": "true",
"id.token.claim": "true",
"access.token.claim": "true",
"claim.name": "minioPolicy",
"jsonType.label": "String",
"user.attribute": "minioPolicy",
multivalued: "false",
},
}
);
console.log("MinIO Policy mapper created successfully.");
}
} catch (error) {
console.error("An error occurred:", error);
// eslint-disable-next-line unicorn/no-process-exit
process.exit(1);
}
};
main();

View File

@@ -0,0 +1,76 @@
import KcAdminClient from "@keycloak/keycloak-admin-client";
import invariant from "tiny-invariant";
const main = async () => {
const keycloakHost = process.env.KEYCLOAK_HOST;
invariant(keycloakHost, "KEYCLOAK_HOST environment variable is required.");
const adminUsername = process.env.KEYCLOAK_ADMIN_USER;
invariant(adminUsername, "KEYCLOAK_ADMIN_USER environment variable is required.");
const adminPassword = process.env.KEYCLOAK_ADMIN_PASSWORD;
invariant(adminPassword, "KEYCLOAK_ADMIN_PASSWORD environment variable is required");
const realmName = process.env.KEYCLOAK_REALM;
invariant(realmName, "KEYCLOAK_REALM environment variable is required");
const username = process.env.USERNAME;
invariant(username, "USERNAME environment variable is required");
const groupName = process.env.GROUP_NAME;
invariant(groupName, "GROUP_NAME environment variable is required");
const kcAdminClient = new KcAdminClient({
baseUrl: `https://${keycloakHost}`,
realmName: "master",
});
try {
await kcAdminClient.auth({
username: adminUsername,
password: adminPassword,
grantType: "password",
clientId: "admin-cli",
});
console.log("Authentication successful.");
kcAdminClient.setConfig({ realmName });
// Find user
const users = await kcAdminClient.users.find({ username });
const user = users.find(u => u.username === username);
if (!user) {
throw new Error(`User '${username}' not found`);
}
// Find group
const groups = await kcAdminClient.groups.find({ search: groupName });
const group = groups.find(g => g.name === groupName);
if (!group) {
throw new Error(`Group '${groupName}' not found`);
}
// Check if user is already in group
const userGroups = await kcAdminClient.users.listGroups({ id: user.id! });
const isAlreadyMember = userGroups.some(ug => ug.id === group.id);
if (isAlreadyMember) {
console.log(`User '${username}' is already a member of group '${groupName}'`);
return;
}
// Add user to group
await kcAdminClient.users.addToGroup({
id: user.id!,
groupId: group.id!,
});
console.log(`User '${username}' added to group '${groupName}' successfully`);
} catch (error) {
console.error("Error adding user to group:", error);
// eslint-disable-next-line unicorn/no-process-exit
process.exit(1);
}
};
main();

View File

@@ -0,0 +1,64 @@
import KcAdminClient from "@keycloak/keycloak-admin-client";
import invariant from "tiny-invariant";
const main = async () => {
const keycloakHost = process.env.KEYCLOAK_HOST;
invariant(keycloakHost, "KEYCLOAK_HOST environment variable is required.");
const adminUsername = process.env.KEYCLOAK_ADMIN_USER;
invariant(adminUsername, "KEYCLOAK_ADMIN_USER environment variable is required.");
const adminPassword = process.env.KEYCLOAK_ADMIN_PASSWORD;
invariant(adminPassword, "KEYCLOAK_ADMIN_PASSWORD environment variable is required");
const realmName = process.env.KEYCLOAK_REALM;
invariant(realmName, "KEYCLOAK_REALM environment variable is required");
const clientId = process.env.KEYCLOAK_CLIENT_ID;
invariant(clientId, "KEYCLOAK_CLIENT_ID environment variable is required");
const clientSecret = process.env.KEYCLOAK_CLIENT_SECRET;
const redirectUrl = process.env.KEYCLOAK_REDIRECT_URL;
invariant(redirectUrl, "KEYCLOAK_REDIRECT_URL environment variable is required");
const redirectUris = redirectUrl.split(',').map(url => url.trim());
const kcAdminClient = new KcAdminClient({
baseUrl: `https://${keycloakHost}`,
realmName: "master",
});
try {
await kcAdminClient.auth({
username: adminUsername,
password: adminPassword,
grantType: "password",
clientId: "admin-cli",
});
console.log("Authentication successful.");
kcAdminClient.setConfig({ realmName });
const existingClients = await kcAdminClient.clients.find({ clientId });
if (existingClients.length > 0) {
console.warn(`Client '${clientId}' already exists.`);
return;
}
const createdClient = await kcAdminClient.clients.create({
clientId: clientId,
secret: clientSecret,
enabled: true,
redirectUris: redirectUris,
publicClient: clientSecret && clientSecret !== '' ? false : true,
});
console.log(`Client created successfully with ID: ${createdClient.id}`);
} catch (error) {
console.error("An error occurred:", error);
// eslint-disable-next-line unicorn/no-process-exit
process.exit(1);
}
};
main();

View File

@@ -0,0 +1,82 @@
import KcAdminClient from "@keycloak/keycloak-admin-client";
import invariant from "tiny-invariant";
const main = async () => {
const keycloakHost = process.env.KEYCLOAK_HOST;
invariant(keycloakHost, "KEYCLOAK_HOST environment variable is required.");
const adminUsername = process.env.KEYCLOAK_ADMIN_USER;
invariant(adminUsername, "KEYCLOAK_ADMIN_USER environment variable is required.");
const adminPassword = process.env.KEYCLOAK_ADMIN_PASSWORD;
invariant(adminPassword, "KEYCLOAK_ADMIN_PASSWORD environment variable is required");
const realmName = process.env.KEYCLOAK_REALM;
invariant(realmName, "KEYCLOAK_REALM environment variable is required");
const groupName = process.env.GROUP_NAME;
invariant(groupName, "GROUP_NAME environment variable is required");
const parentGroupName = process.env.PARENT_GROUP_NAME || "";
const groupDescription = process.env.GROUP_DESCRIPTION || "";
const kcAdminClient = new KcAdminClient({
baseUrl: `https://${keycloakHost}`,
realmName: "master",
});
try {
await kcAdminClient.auth({
username: adminUsername,
password: adminPassword,
grantType: "password",
clientId: "admin-cli",
});
console.log("Authentication successful.");
kcAdminClient.setConfig({ realmName });
// Check if group already exists
const existingGroups = await kcAdminClient.groups.find({ search: groupName });
const existingGroup = existingGroups.find(group => group.name === groupName);
if (existingGroup) {
console.log(`Group '${groupName}' already exists with ID: ${existingGroup.id}`);
return;
}
// Find parent group if specified
let parentGroupId: string | undefined;
if (parentGroupName) {
const parentGroups = await kcAdminClient.groups.find({ search: parentGroupName });
const parentGroup = parentGroups.find(group => group.name === parentGroupName);
if (!parentGroup) {
throw new Error(`Parent group '${parentGroupName}' not found`);
}
parentGroupId = parentGroup.id;
}
// Create group payload
const groupPayload = {
name: groupName,
...(groupDescription && { attributes: { description: [groupDescription] } }),
};
// Create group
const group = parentGroupId
? await kcAdminClient.groups.createChildGroup({ id: parentGroupId }, groupPayload)
: await kcAdminClient.groups.create(groupPayload);
console.log(`Group '${groupName}' created successfully with ID: ${group.id}`);
if (parentGroupName) {
console.log(`Group '${groupName}' created as child of '${parentGroupName}'`);
}
} catch (error) {
console.error("Error creating group:", error);
// eslint-disable-next-line unicorn/no-process-exit
process.exit(1);
}
};
main();

View File

@@ -0,0 +1,50 @@
import KcAdminClient from "@keycloak/keycloak-admin-client";
import invariant from "tiny-invariant";
const main = async () => {
const keycloakHost = process.env.KEYCLOAK_HOST;
invariant(keycloakHost, "KEYCLOAK_HOST environment variable is required.");
const adminUsername = process.env.KEYCLOAK_ADMIN_USER;
invariant(adminUsername, "KEYCLOAK_ADMIN_USER environment variable is required.");
const adminPassword = process.env.KEYCLOAK_ADMIN_PASSWORD;
invariant(adminPassword, "KEYCLOAK_ADMIN_PASSWORD environment variable is required");
const realmName = process.env.KEYCLOAK_REALM;
invariant(realmName, "KEYCLOAK_REALM environment variable is required");
const kcAdminClient = new KcAdminClient({
baseUrl: `https://${keycloakHost}`,
realmName: "master",
});
try {
await kcAdminClient.auth({
username: adminUsername,
password: adminPassword,
grantType: "password",
clientId: "admin-cli",
});
console.log("Authentication successful.");
const existingRealms = await kcAdminClient.realms.find();
const realmExists = existingRealms.some((realm) => realm.realm === realmName);
if (realmExists) {
console.warn(`Realm '${realmName}' already exists.`);
return;
}
await kcAdminClient.realms.create({
realm: realmName,
enabled: true,
});
console.log(`Realm '${realmName}' created successfully.`);
} catch (error) {
console.error("An error occurred:", error);
// eslint-disable-next-line unicorn/no-process-exit
process.exit(1);
}
};
main();

View File

@@ -0,0 +1,99 @@
import KcAdminClient from "@keycloak/keycloak-admin-client";
import invariant from "tiny-invariant";
const main = async () => {
const keycloakHost = process.env.KEYCLOAK_HOST;
invariant(keycloakHost, "KEYCLOAK_HOST environment variable is required.");
const adminUsername = process.env.KEYCLOAK_ADMIN_USER;
invariant(adminUsername, "KEYCLOAK_ADMIN_USER environment variable is required.");
const adminPassword = process.env.KEYCLOAK_ADMIN_PASSWORD;
invariant(adminPassword, "KEYCLOAK_ADMIN_PASSWORD environment variable is required");
const realmName = process.env.KEYCLOAK_REALM;
invariant(realmName, "KEYCLOAK_REALM environment variable is required");
const username = process.env.USERNAME;
invariant(username, "USERNAME environment variable is required");
const email = process.env.EMAIL;
const firstName = process.env.FIRST_NAME;
const lastName = process.env.LAST_NAME;
const password = process.env.PASSWORD;
invariant(password, "PASSWORD environment variable is required");
const createAsAdmin = process.env.CREATE_AS_ADMIN === "true";
const kcAdminClient = new KcAdminClient({
baseUrl: `https://${keycloakHost}`,
realmName: "master",
});
try {
await kcAdminClient.auth({
username: adminUsername,
password: adminPassword,
grantType: "password",
clientId: "admin-cli",
});
console.log("Authentication successful.");
kcAdminClient.setConfig({ realmName });
const userPayload = {
username,
email,
emailVerified: true,
firstName,
lastName,
enabled: true,
};
const user = await kcAdminClient.users.create(userPayload);
console.log(`User created successfully with ID: ${user.id}`);
if (createAsAdmin && realmName === "master") {
const adminRole = await kcAdminClient.roles.findOneByName({
realm: "master",
name: "admin",
});
const createRealmRole = await kcAdminClient.roles.findOneByName({
realm: "master",
name: "create-realm",
});
await kcAdminClient.users.addRealmRoleMappings({
realm: "master",
id: user.id,
roles: [
{
id: adminRole!.id!,
name: adminRole!.name!,
},
{
id: createRealmRole!.id!,
name: createRealmRole!.name!,
},
],
});
}
await kcAdminClient.users.resetPassword({
id: user.id!,
credential: {
type: "password",
value: password,
temporary: false,
},
});
console.log(`Password set for user '${user.id}'.`);
} catch (error) {
console.error("Error creating user:", error);
// eslint-disable-next-line unicorn/no-process-exit
process.exit(1);
}
};
main();

View File

@@ -0,0 +1,54 @@
import KcAdminClient from "@keycloak/keycloak-admin-client";
import invariant from "tiny-invariant";
const main = async () => {
const keycloakHost = process.env.KEYCLOAK_HOST;
invariant(keycloakHost, "KEYCLOAK_HOST environment variable is required.");
const adminUsername = process.env.KEYCLOAK_ADMIN_USER;
invariant(adminUsername, "KEYCLOAK_ADMIN_USER environment variable is required.");
const adminPassword = process.env.KEYCLOAK_ADMIN_PASSWORD;
invariant(adminPassword, "KEYCLOAK_ADMIN_PASSWORD environment variable is required");
const realmName = process.env.KEYCLOAK_REALM;
invariant(realmName, "KEYCLOAK_REALM environment variable is required");
const clientId = process.env.KEYCLOAK_CLIENT_ID;
invariant(clientId, "KEYCLOAK_CLIENT_ID environment variable is required");
const kcAdminClient = new KcAdminClient({
baseUrl: `https://${keycloakHost}`,
realmName: 'master',
});
try {
await kcAdminClient.auth({
username: adminUsername,
password: adminPassword,
grantType: "password",
clientId: "admin-cli",
});
console.log("Authentication successful.");
kcAdminClient.setConfig({ realmName });
const existingClients = await kcAdminClient.clients.find({ clientId });
if (existingClients.length === 0) {
console.warn(`Client '${clientId}' does not exist.`);
return;
}
const client = existingClients[0];
invariant(client.id, "Client ID is not set");
await kcAdminClient.clients.del({ id: client.id });
console.log(`Client '${clientId}' successfully deleted.`);
} catch (error) {
console.error("An error occurred:", error);
// eslint-disable-next-line unicorn/no-process-exit
process.exit(1);
}
};
main();

View File

@@ -0,0 +1,76 @@
import KcAdminClient from "@keycloak/keycloak-admin-client";
import invariant from "tiny-invariant";
const main = async () => {
const keycloakHost = process.env.KEYCLOAK_HOST;
invariant(keycloakHost, "KEYCLOAK_HOST environment variable is required.");
const adminUsername = process.env.KEYCLOAK_ADMIN_USER;
invariant(adminUsername, "KEYCLOAK_ADMIN_USER environment variable is required.");
const adminPassword = process.env.KEYCLOAK_ADMIN_PASSWORD;
invariant(adminPassword, "KEYCLOAK_ADMIN_PASSWORD environment variable is required");
const realmName = process.env.KEYCLOAK_REALM;
invariant(realmName, "KEYCLOAK_REALM environment variable is required");
const groupName = process.env.GROUP_NAME;
invariant(groupName, "GROUP_NAME environment variable is required");
const kcAdminClient = new KcAdminClient({
baseUrl: `https://${keycloakHost}`,
realmName: "master",
});
try {
await kcAdminClient.auth({
username: adminUsername,
password: adminPassword,
grantType: "password",
clientId: "admin-cli",
});
console.log("Authentication successful.");
kcAdminClient.setConfig({ realmName });
// Find group to delete
const groups = await kcAdminClient.groups.find({ search: groupName });
const group = groups.find(g => g.name === groupName);
if (!group) {
console.log(`Group '${groupName}' not found`);
return;
}
// Check if group has members
const groupMembers = await kcAdminClient.groups.listMembers({ id: group.id! });
if (groupMembers.length > 0) {
console.log(`Warning: Group '${groupName}' has ${groupMembers.length} members:`);
groupMembers.forEach(member => {
console.log(` - ${member.username} (${member.firstName} ${member.lastName})`);
});
console.log("All members will be removed from the group when it's deleted.");
}
// Check for subgroups
const subGroups = await kcAdminClient.groups.listSubGroups({ id: group.id! });
if (subGroups.length > 0) {
console.log(`Warning: Group '${groupName}' has ${subGroups.length} subgroups:`);
subGroups.forEach(subGroup => {
console.log(` - ${subGroup.name}`);
});
console.log("All subgroups will be deleted as well.");
}
// Delete group
await kcAdminClient.groups.del({ id: group.id! });
console.log(`Group '${groupName}' deleted successfully`);
} catch (error) {
console.error("Error deleting group:", error);
// eslint-disable-next-line unicorn/no-process-exit
process.exit(1);
}
};
main();

View File

@@ -0,0 +1,61 @@
import KcAdminClient from "@keycloak/keycloak-admin-client";
import invariant from "tiny-invariant";
const main = async () => {
const keycloakHost = process.env.KEYCLOAK_HOST;
invariant(keycloakHost, "KEYCLOAK_HOST environment variable is required.");
const adminUsername = process.env.KEYCLOAK_ADMIN_USER;
invariant(adminUsername, "KEYCLOAK_ADMIN_USER environment variable is required.");
const adminPassword = process.env.KEYCLOAK_ADMIN_PASSWORD;
invariant(adminPassword, "KEYCLOAK_ADMIN_PASSWORD environment variable is required");
const realmNameToDelete = process.env.KEYCLOAK_REALM_TO_DELETE;
invariant(realmNameToDelete, "KEYCLOAK_REALM_TO_DELETE environment variable is required");
if (realmNameToDelete === "master") {
console.error("Error: Deleting the 'master' realm is a highly destructive operation and is not allowed by this script.");
// eslint-disable-next-line unicorn/no-process-exit
process.exit(1);
}
const kcAdminClient = new KcAdminClient({
baseUrl: `https://${keycloakHost}`,
realmName: "master", // Authenticate against master realm to delete other realms
});
try {
await kcAdminClient.auth({
username: adminUsername,
password: adminPassword,
grantType: "password",
clientId: "admin-cli",
});
console.log("Authentication successful with master realm.");
// Check if realm exists before attempting deletion
const realm = await kcAdminClient.realms.findOne({ realm: realmNameToDelete });
if (!realm) {
console.warn(`Realm '${realmNameToDelete}' not found. Nothing to delete.`);
return; // Exit gracefully if realm doesn't exist
}
console.log(`Attempting to delete realm: '${realmNameToDelete}'...`);
await kcAdminClient.realms.del({ realm: realmNameToDelete });
console.log(`Realm '${realmNameToDelete}' deleted successfully.`);
} catch (error) {
console.error(`An error occurred while trying to delete realm '${realmNameToDelete}':`, error);
const err = error as any;
if (err.response?.data) {
console.error("Error details:", JSON.stringify(err.response.data, undefined, 2));
}
// eslint-disable-next-line unicorn/no-process-exit
process.exit(1);
}
};
main();

View File

@@ -0,0 +1,76 @@
import KcAdminClient from "@keycloak/keycloak-admin-client";
import invariant from "tiny-invariant";
const main = async () => {
const keycloakHost = process.env.KEYCLOAK_HOST;
invariant(keycloakHost, "KEYCLOAK_HOST environment variable is required.");
const adminUsername = process.env.KEYCLOAK_ADMIN_USER;
invariant(adminUsername, "KEYCLOAK_ADMIN_USER environment variable is required.");
const adminPassword = process.env.KEYCLOAK_ADMIN_PASSWORD;
invariant(adminPassword, "KEYCLOAK_ADMIN_PASSWORD environment variable is required");
const realmName = process.env.KEYCLOAK_REALM;
invariant(realmName, "KEYCLOAK_REALM environment variable is required");
const username = process.env.USERNAME;
invariant(username, "USERNAME environment variable is required");
const groupName = process.env.GROUP_NAME;
invariant(groupName, "GROUP_NAME environment variable is required");
const kcAdminClient = new KcAdminClient({
baseUrl: `https://${keycloakHost}`,
realmName: "master",
});
try {
await kcAdminClient.auth({
username: adminUsername,
password: adminPassword,
grantType: "password",
clientId: "admin-cli",
});
console.log("Authentication successful.");
kcAdminClient.setConfig({ realmName });
// Find user
const users = await kcAdminClient.users.find({ username });
const user = users.find(u => u.username === username);
if (!user) {
throw new Error(`User '${username}' not found`);
}
// Find group
const groups = await kcAdminClient.groups.find({ search: groupName });
const group = groups.find(g => g.name === groupName);
if (!group) {
throw new Error(`Group '${groupName}' not found`);
}
// Check if user is in group
const userGroups = await kcAdminClient.users.listGroups({ id: user.id! });
const isMember = userGroups.some(ug => ug.id === group.id);
if (!isMember) {
console.log(`User '${username}' is not a member of group '${groupName}'`);
return;
}
// Remove user from group
await kcAdminClient.users.delFromGroup({
id: user.id!,
groupId: group.id!,
});
console.log(`User '${username}' removed from group '${groupName}' successfully`);
} catch (error) {
console.error("Error removing user from group:", error);
// eslint-disable-next-line unicorn/no-process-exit
process.exit(1);
}
};
main();

View File

@@ -0,0 +1,60 @@
import KcAdminClient from "@keycloak/keycloak-admin-client";
import invariant from "tiny-invariant";
const main = async () => {
const keycloakHost = process.env.KEYCLOAK_HOST;
invariant(keycloakHost, "KEYCLOAK_HOST environment variable is required.");
const adminUsername = process.env.KEYCLOAK_ADMIN_USER;
invariant(adminUsername, "KEYCLOAK_ADMIN_USER environment variable is required.");
const adminPassword = process.env.KEYCLOAK_ADMIN_PASSWORD;
invariant(adminPassword, "KEYCLOAK_ADMIN_PASSWORD environment variable is required");
const realmName = process.env.KEYCLOAK_REALM;
invariant(realmName, "KEYCLOAK_REALM environment variable is required");
const usernameToDelete = process.env.USERNAME;
invariant(
usernameToDelete,
"USERNAME environment variable (for the user to be deleted) is required"
);
const kcAdminClient = new KcAdminClient({
baseUrl: `https://${keycloakHost}`,
realmName: "master",
});
try {
await kcAdminClient.auth({
username: adminUsername,
password: adminPassword,
grantType: "password",
clientId: "admin-cli",
});
console.log("Authentication successful.");
kcAdminClient.setConfig({ realmName });
const users = await kcAdminClient.users.find({ username: usernameToDelete });
if (users.length === 0) {
console.warn(`User '${usernameToDelete}' not found in realm '${realmName}'.`);
return;
}
const user = users[0];
invariant(user.id, `User ID not found for user '${usernameToDelete}'.`);
await kcAdminClient.users.del({ id: user.id });
console.log(
`User '${usernameToDelete}' (ID: ${user.id}) successfully deleted from realm '${realmName}'.`
);
} catch (error) {
console.error("An error occurred during user deletion:", error);
// eslint-disable-next-line unicorn/no-process-exit
process.exit(1);
}
};
main();

View File

@@ -0,0 +1,57 @@
import KcAdminClient from "@keycloak/keycloak-admin-client";
import invariant from "tiny-invariant";
const main = async () => {
const keycloakHost = process.env.KEYCLOAK_HOST;
invariant(keycloakHost, "KEYCLOAK_HOST environment variable is required.");
const adminUsername = process.env.KEYCLOAK_ADMIN_USER;
invariant(adminUsername, "KEYCLOAK_ADMIN_USER environment variable is required.");
const adminPassword = process.env.KEYCLOAK_ADMIN_PASSWORD;
invariant(adminPassword, "KEYCLOAK_ADMIN_PASSWORD environment variable is required");
const realmName = process.env.KEYCLOAK_REALM;
invariant(realmName, "KEYCLOAK_REALM environment variable is required");
const username = process.env.USERNAME;
invariant(username, "USERNAME environment variable is required");
const kcAdminClient = new KcAdminClient({
baseUrl: `https://${keycloakHost}`,
realmName: "master",
});
try {
await kcAdminClient.auth({
username: adminUsername,
password: adminPassword,
grantType: "password",
clientId: "admin-cli",
});
console.log("Authentication successful.");
kcAdminClient.setConfig({ realmName });
const users = await kcAdminClient.users.find({
username,
exact: true,
});
if (users && users.length > 0) {
console.log(`User '${username}' exists with ID: ${users[0].id}`);
// eslint-disable-next-line unicorn/no-process-exit
process.exit(0);
} else {
console.log(`User '${username}' does not exist.`);
// eslint-disable-next-line unicorn/no-process-exit
process.exit(1);
}
} catch (error) {
console.error("Error checking user existence:", error);
// eslint-disable-next-line unicorn/no-process-exit
process.exit(1);
}
};
main();