chore(keycloak): code cleanup
This commit is contained in:
@@ -26,7 +26,6 @@ const main = async () => {
|
||||
const attributeDefaultValue = process.env.ATTRIBUTE_DEFAULT_VALUE;
|
||||
const mapperName = process.env.MAPPER_NAME || `${attributeDisplayName} Mapper`;
|
||||
|
||||
// Parse permissions from environment variables
|
||||
const viewPermissions = process.env.ATTRIBUTE_VIEW_PERMISSIONS?.split(",") || ["admin", "user"];
|
||||
const editPermissions = process.env.ATTRIBUTE_EDIT_PERMISSIONS?.split(",") || ["admin"];
|
||||
|
||||
@@ -58,19 +57,13 @@ const main = async () => {
|
||||
});
|
||||
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 attribute already exists
|
||||
const existingAttribute = userProfile.attributes?.find(
|
||||
(attr: any) => attr.name === attributeName
|
||||
);
|
||||
|
||||
if (existingAttribute) {
|
||||
console.log(`${attributeName} attribute already exists in User Profile.`);
|
||||
} else {
|
||||
@@ -88,16 +81,13 @@ const main = async () => {
|
||||
},
|
||||
};
|
||||
|
||||
// Add validations if options are provided
|
||||
if (attributeOptions && attributeOptions.length > 0) {
|
||||
attributeConfig.validations = {
|
||||
options: { options: attributeOptions },
|
||||
};
|
||||
}
|
||||
|
||||
userProfile.attributes.push(attributeConfig);
|
||||
|
||||
// Update User Profile
|
||||
await kcAdminClient.users.updateProfile(userProfile);
|
||||
console.log(
|
||||
`${attributeName} attribute added to User Profile successfully with admin edit permissions.`
|
||||
@@ -114,14 +104,14 @@ const main = async () => {
|
||||
const clientInternalId = client[0].id;
|
||||
invariant(clientInternalId, "Client internal ID is required");
|
||||
|
||||
// Check if the mapper already exists
|
||||
const mappers = await kcAdminClient.clients.listProtocolMappers({ id: clientInternalId });
|
||||
const mappers = await kcAdminClient.clients.listProtocolMappers({
|
||||
id: clientInternalId,
|
||||
});
|
||||
const existingMapper = mappers.find((mapper) => mapper.name === mapperName);
|
||||
|
||||
if (existingMapper) {
|
||||
console.log(`${mapperName} already exists.`);
|
||||
} else {
|
||||
// Create the protocol mapper
|
||||
await kcAdminClient.clients.addProtocolMapper(
|
||||
{ id: clientInternalId },
|
||||
{
|
||||
|
||||
@@ -1,80 +1,75 @@
|
||||
#!/usr/bin/env tsx
|
||||
|
||||
import KcAdminClient from '@keycloak/keycloak-admin-client';
|
||||
import invariant from 'tiny-invariant';
|
||||
import KcAdminClient from "@keycloak/keycloak-admin-client";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
const main = async () => {
|
||||
const KEYCLOAK_HOST = process.env.KEYCLOAK_HOST;
|
||||
const KEYCLOAK_ADMIN_USER = process.env.KEYCLOAK_ADMIN_USER;
|
||||
const KEYCLOAK_ADMIN_PASSWORD = process.env.KEYCLOAK_ADMIN_PASSWORD;
|
||||
const realm = process.env.KEYCLOAK_REALM;
|
||||
const scopeName = process.env.SCOPE_NAME;
|
||||
const audience = process.env.KEYCLOAK_AUDIENCE;
|
||||
const KEYCLOAK_HOST = process.env.KEYCLOAK_HOST;
|
||||
const KEYCLOAK_ADMIN_USER = process.env.KEYCLOAK_ADMIN_USER;
|
||||
const KEYCLOAK_ADMIN_PASSWORD = process.env.KEYCLOAK_ADMIN_PASSWORD;
|
||||
const realm = process.env.KEYCLOAK_REALM;
|
||||
const scopeName = process.env.SCOPE_NAME;
|
||||
const audience = process.env.KEYCLOAK_AUDIENCE;
|
||||
|
||||
invariant(KEYCLOAK_HOST, 'KEYCLOAK_HOST environment variable is required');
|
||||
invariant(KEYCLOAK_ADMIN_USER, 'KEYCLOAK_ADMIN_USER environment variable is required');
|
||||
invariant(KEYCLOAK_ADMIN_PASSWORD, 'KEYCLOAK_ADMIN_PASSWORD environment variable is required');
|
||||
invariant(realm, 'KEYCLOAK_REALM environment variable is required');
|
||||
invariant(scopeName, 'SCOPE_NAME environment variable is required');
|
||||
invariant(audience, 'KEYCLOAK_AUDIENCE environment variable is required');
|
||||
invariant(KEYCLOAK_HOST, "KEYCLOAK_HOST environment variable is required");
|
||||
invariant(KEYCLOAK_ADMIN_USER, "KEYCLOAK_ADMIN_USER environment variable is required");
|
||||
invariant(KEYCLOAK_ADMIN_PASSWORD, "KEYCLOAK_ADMIN_PASSWORD environment variable is required");
|
||||
invariant(realm, "KEYCLOAK_REALM environment variable is required");
|
||||
invariant(scopeName, "SCOPE_NAME environment variable is required");
|
||||
invariant(audience, "KEYCLOAK_AUDIENCE environment variable is required");
|
||||
|
||||
const kcAdminClient = new KcAdminClient({
|
||||
baseUrl: `https://${KEYCLOAK_HOST}`,
|
||||
realmName: 'master',
|
||||
const kcAdminClient = new KcAdminClient({
|
||||
baseUrl: `https://${KEYCLOAK_HOST}`,
|
||||
realmName: "master",
|
||||
});
|
||||
|
||||
try {
|
||||
await kcAdminClient.auth({
|
||||
username: KEYCLOAK_ADMIN_USER,
|
||||
password: KEYCLOAK_ADMIN_PASSWORD,
|
||||
grantType: "password",
|
||||
clientId: "admin-cli",
|
||||
});
|
||||
|
||||
try {
|
||||
await kcAdminClient.auth({
|
||||
username: KEYCLOAK_ADMIN_USER,
|
||||
password: KEYCLOAK_ADMIN_PASSWORD,
|
||||
grantType: 'password',
|
||||
clientId: 'admin-cli',
|
||||
});
|
||||
console.log("Authentication successful.");
|
||||
|
||||
console.log('Authentication successful.');
|
||||
kcAdminClient.setConfig({
|
||||
realmName: realm,
|
||||
});
|
||||
|
||||
// Set target realm
|
||||
kcAdminClient.setConfig({
|
||||
realmName: realm,
|
||||
});
|
||||
|
||||
// Find the client scope
|
||||
const clientScopes = await kcAdminClient.clientScopes.find();
|
||||
const scope = clientScopes.find(s => s.name === scopeName);
|
||||
if (!scope) {
|
||||
throw new Error(`Client scope '${scopeName}' not found`);
|
||||
}
|
||||
|
||||
invariant(scope.id, 'Client scope ID is not set');
|
||||
|
||||
// Check if mapper already exists
|
||||
const mapperName = `aud-mapper-${audience}`;
|
||||
const existingMappers = await kcAdminClient.clientScopes.listProtocolMappers({ id: scope.id });
|
||||
|
||||
if (existingMappers.some((mapper) => mapper.name === mapperName)) {
|
||||
console.warn(`Audience mapper '${mapperName}' already exists in scope '${scopeName}'.`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Create audience mapper
|
||||
const audienceMapper = {
|
||||
name: mapperName,
|
||||
protocol: 'openid-connect',
|
||||
protocolMapper: 'oidc-audience-mapper',
|
||||
config: {
|
||||
'included.client.audience': audience,
|
||||
'id.token.claim': 'false',
|
||||
'access.token.claim': 'true',
|
||||
},
|
||||
};
|
||||
|
||||
await kcAdminClient.clientScopes.addProtocolMapper({ id: scope.id }, audienceMapper);
|
||||
console.log(`Audience mapper '${mapperName}' added to client scope '${scopeName}'.`);
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error adding audience mapper to scope:', error);
|
||||
process.exit(1);
|
||||
const clientScopes = await kcAdminClient.clientScopes.find();
|
||||
const scope = clientScopes.find((s) => s.name === scopeName);
|
||||
if (!scope) {
|
||||
throw new Error(`Client scope '${scopeName}' not found`);
|
||||
}
|
||||
|
||||
invariant(scope.id, "Client scope ID is not set");
|
||||
|
||||
const mapperName = `aud-mapper-${audience}`;
|
||||
const existingMappers = await kcAdminClient.clientScopes.listProtocolMappers({ id: scope.id });
|
||||
|
||||
if (existingMappers.some((mapper) => mapper.name === mapperName)) {
|
||||
console.warn(`Audience mapper '${mapperName}' already exists in scope '${scopeName}'.`);
|
||||
return;
|
||||
}
|
||||
|
||||
const audienceMapper = {
|
||||
name: mapperName,
|
||||
protocol: "openid-connect",
|
||||
protocolMapper: "oidc-audience-mapper",
|
||||
config: {
|
||||
"included.client.audience": audience,
|
||||
"id.token.claim": "false",
|
||||
"access.token.claim": "true",
|
||||
},
|
||||
};
|
||||
|
||||
await kcAdminClient.clientScopes.addProtocolMapper({ id: scope.id }, audienceMapper);
|
||||
console.log(`Audience mapper '${mapperName}' added to client scope '${scopeName}'.`);
|
||||
} catch (error) {
|
||||
console.error("Error adding audience mapper to scope:", error);
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
main();
|
||||
|
||||
@@ -55,7 +55,9 @@ const main = async () => {
|
||||
},
|
||||
};
|
||||
|
||||
const existingMappers = await kcAdminClient.clients.listProtocolMappers({ id: client.id });
|
||||
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.`);
|
||||
|
||||
@@ -35,12 +35,10 @@ async function main() {
|
||||
clientId: "admin-cli",
|
||||
});
|
||||
|
||||
// Set realm to work with
|
||||
kcAdminClient.setConfig({
|
||||
realmName,
|
||||
});
|
||||
|
||||
// Find the client
|
||||
const clients = await kcAdminClient.clients.find({ clientId });
|
||||
if (clients.length === 0) {
|
||||
throw new Error(`Client '${clientId}' not found in realm '${realmName}'`);
|
||||
@@ -49,8 +47,9 @@ async function main() {
|
||||
const client = clients[0];
|
||||
const clientInternalId = client.id!;
|
||||
|
||||
// Check if the mapper already exists
|
||||
const mappers = await kcAdminClient.clients.listProtocolMappers({ id: clientInternalId });
|
||||
const mappers = await kcAdminClient.clients.listProtocolMappers({
|
||||
id: clientInternalId,
|
||||
});
|
||||
const existingMapper = mappers.find((mapper) => mapper.name === mapperName);
|
||||
|
||||
if (existingMapper) {
|
||||
@@ -58,7 +57,6 @@ async function main() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Create the client roles protocol mapper
|
||||
await kcAdminClient.clients.addProtocolMapper(
|
||||
{ id: clientInternalId },
|
||||
{
|
||||
@@ -71,13 +69,15 @@ async function main() {
|
||||
"access.token.claim": "true",
|
||||
"claim.name": claimName,
|
||||
"jsonType.label": "String",
|
||||
"multivalued": "true",
|
||||
multivalued: "true",
|
||||
"usermodel.clientRoleMapping.clientId": clientId,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
console.log(`✓ Client roles mapper '${mapperName}' created for client '${clientId}' in realm '${realmName}'`);
|
||||
console.log(
|
||||
`✓ Client roles mapper '${mapperName}' created for client '${clientId}' in realm '${realmName}'`
|
||||
);
|
||||
console.log(` Claim name: ${claimName}`);
|
||||
console.log(` Maps client roles from '${clientId}' to JWT token`);
|
||||
} catch (error) {
|
||||
@@ -86,4 +86,4 @@ async function main() {
|
||||
}
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
||||
main().catch(console.error);
|
||||
|
||||
@@ -26,38 +26,31 @@ async function main() {
|
||||
kcAdminClient.setConfig({ realmName: realm });
|
||||
|
||||
try {
|
||||
// Find the profile client scope
|
||||
const clientScopes = await kcAdminClient.clientScopes.find({ realm });
|
||||
const profileScope = clientScopes.find(scope => scope.name === 'profile');
|
||||
const profileScope = clientScopes.find((scope) => scope.name === "profile");
|
||||
|
||||
if (!profileScope) {
|
||||
throw new Error("Profile client scope not found");
|
||||
}
|
||||
|
||||
console.log(`Found profile scope: ${profileScope.id}`);
|
||||
|
||||
// Check existing mappers in profile scope
|
||||
const existingMappers = await kcAdminClient.clientScopes.listProtocolMappers({
|
||||
realm,
|
||||
id: profileScope.id!,
|
||||
});
|
||||
|
||||
console.log("Existing mappers in profile scope:");
|
||||
existingMappers.forEach(mapper => {
|
||||
existingMappers.forEach((mapper) => {
|
||||
console.log(`- ${mapper.name} (${mapper.protocolMapper})`);
|
||||
});
|
||||
|
||||
// Check if our client roles mapper already exists in profile scope
|
||||
const clientRolesMapper = existingMappers.find(m =>
|
||||
m.config?.['usermodel.clientRoleMapping.clientId'] === clientId
|
||||
const clientRolesMapper = existingMappers.find(
|
||||
(m) => m.config?.["usermodel.clientRoleMapping.clientId"] === clientId
|
||||
);
|
||||
|
||||
if (clientRolesMapper) {
|
||||
console.log(`Client roles mapper already exists in profile scope: ${clientRolesMapper.name}`);
|
||||
} else {
|
||||
console.log(`Adding ${clientId} client roles mapper to profile scope...`);
|
||||
|
||||
// Add client roles mapper to profile scope
|
||||
await kcAdminClient.clientScopes.addProtocolMapper(
|
||||
{ realm, id: profileScope.id! },
|
||||
{
|
||||
@@ -70,7 +63,7 @@ async function main() {
|
||||
"access.token.claim": "true",
|
||||
"claim.name": claimName,
|
||||
"jsonType.label": "String",
|
||||
"multivalued": "true",
|
||||
multivalued: "true",
|
||||
"usermodel.clientRoleMapping.clientId": clientId,
|
||||
},
|
||||
}
|
||||
@@ -78,11 +71,10 @@ async function main() {
|
||||
|
||||
console.log(`✓ Added ${clientId} client roles mapper to profile scope`);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error(`Error: ${error}`);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
||||
main().catch(console.error);
|
||||
|
||||
@@ -33,43 +33,41 @@ const main = async () => {
|
||||
|
||||
kcAdminClient.setConfig({ realmName });
|
||||
|
||||
// Find the client
|
||||
const clients = await kcAdminClient.clients.find({ clientId });
|
||||
const client = clients.find(c => c.clientId === clientId);
|
||||
|
||||
const client = clients.find((c) => c.clientId === clientId);
|
||||
if (!client) {
|
||||
throw new Error(`Client '${clientId}' not found`);
|
||||
}
|
||||
|
||||
// Check if groups mapper already exists
|
||||
const existingMappers = await kcAdminClient.clients.listProtocolMappers({
|
||||
id: client.id!,
|
||||
});
|
||||
|
||||
const groupsMapper = existingMappers.find(mapper =>
|
||||
mapper.name === "groups" || mapper.config?.["claim.name"] === "groups"
|
||||
const groupsMapper = existingMappers.find(
|
||||
(mapper) => mapper.name === "groups" || mapper.config?.["claim.name"] === "groups"
|
||||
);
|
||||
|
||||
if (groupsMapper) {
|
||||
console.log("Groups mapper already exists for the client.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Add groups mapper
|
||||
await kcAdminClient.clients.addProtocolMapper({
|
||||
id: client.id!,
|
||||
}, {
|
||||
name: "groups",
|
||||
protocol: "openid-connect",
|
||||
protocolMapper: "oidc-group-membership-mapper",
|
||||
config: {
|
||||
"claim.name": "groups",
|
||||
"full.path": "false",
|
||||
"id.token.claim": "true",
|
||||
"access.token.claim": "true",
|
||||
"userinfo.token.claim": "true",
|
||||
await kcAdminClient.clients.addProtocolMapper(
|
||||
{
|
||||
id: client.id!,
|
||||
},
|
||||
});
|
||||
{
|
||||
name: "groups",
|
||||
protocol: "openid-connect",
|
||||
protocolMapper: "oidc-group-membership-mapper",
|
||||
config: {
|
||||
"claim.name": "groups",
|
||||
"full.path": "false",
|
||||
"id.token.claim": "true",
|
||||
"access.token.claim": "true",
|
||||
"userinfo.token.claim": "true",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
console.log("Groups mapper added to the client.");
|
||||
} catch (error) {
|
||||
@@ -79,4 +77,4 @@ const main = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
main();
|
||||
main();
|
||||
|
||||
@@ -34,15 +34,12 @@ const main = async () => {
|
||||
});
|
||||
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"
|
||||
);
|
||||
@@ -50,11 +47,9 @@ const main = async () => {
|
||||
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",
|
||||
@@ -67,15 +62,15 @@ const main = async () => {
|
||||
},
|
||||
});
|
||||
|
||||
// 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 });
|
||||
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
|
||||
@@ -84,14 +79,14 @@ const main = async () => {
|
||||
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 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 },
|
||||
{
|
||||
|
||||
@@ -1,69 +1,64 @@
|
||||
#!/usr/bin/env tsx
|
||||
|
||||
import KcAdminClient from '@keycloak/keycloak-admin-client';
|
||||
import invariant from 'tiny-invariant';
|
||||
import KcAdminClient from "@keycloak/keycloak-admin-client";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
const main = async () => {
|
||||
const KEYCLOAK_HOST = process.env.KEYCLOAK_HOST;
|
||||
const KEYCLOAK_ADMIN_USER = process.env.KEYCLOAK_ADMIN_USER;
|
||||
const KEYCLOAK_ADMIN_PASSWORD = process.env.KEYCLOAK_ADMIN_PASSWORD;
|
||||
const realm = process.env.KEYCLOAK_REALM;
|
||||
const clientId = process.env.KEYCLOAK_CLIENT_ID;
|
||||
const scopeName = process.env.SCOPE_NAME;
|
||||
const KEYCLOAK_HOST = process.env.KEYCLOAK_HOST;
|
||||
const KEYCLOAK_ADMIN_USER = process.env.KEYCLOAK_ADMIN_USER;
|
||||
const KEYCLOAK_ADMIN_PASSWORD = process.env.KEYCLOAK_ADMIN_PASSWORD;
|
||||
const realm = process.env.KEYCLOAK_REALM;
|
||||
const clientId = process.env.KEYCLOAK_CLIENT_ID;
|
||||
const scopeName = process.env.SCOPE_NAME;
|
||||
|
||||
invariant(KEYCLOAK_HOST, 'KEYCLOAK_HOST environment variable is required');
|
||||
invariant(KEYCLOAK_ADMIN_USER, 'KEYCLOAK_ADMIN_USER environment variable is required');
|
||||
invariant(KEYCLOAK_ADMIN_PASSWORD, 'KEYCLOAK_ADMIN_PASSWORD environment variable is required');
|
||||
invariant(realm, 'KEYCLOAK_REALM environment variable is required');
|
||||
invariant(clientId, 'KEYCLOAK_CLIENT_ID environment variable is required');
|
||||
invariant(scopeName, 'SCOPE_NAME environment variable is required');
|
||||
invariant(KEYCLOAK_HOST, "KEYCLOAK_HOST environment variable is required");
|
||||
invariant(KEYCLOAK_ADMIN_USER, "KEYCLOAK_ADMIN_USER environment variable is required");
|
||||
invariant(KEYCLOAK_ADMIN_PASSWORD, "KEYCLOAK_ADMIN_PASSWORD environment variable is required");
|
||||
invariant(realm, "KEYCLOAK_REALM environment variable is required");
|
||||
invariant(clientId, "KEYCLOAK_CLIENT_ID environment variable is required");
|
||||
invariant(scopeName, "SCOPE_NAME environment variable is required");
|
||||
|
||||
const kcAdminClient = new KcAdminClient({
|
||||
baseUrl: `https://${KEYCLOAK_HOST}`,
|
||||
realmName: 'master',
|
||||
const kcAdminClient = new KcAdminClient({
|
||||
baseUrl: `https://${KEYCLOAK_HOST}`,
|
||||
realmName: "master",
|
||||
});
|
||||
|
||||
try {
|
||||
await kcAdminClient.auth({
|
||||
username: KEYCLOAK_ADMIN_USER,
|
||||
password: KEYCLOAK_ADMIN_PASSWORD,
|
||||
grantType: "password",
|
||||
clientId: "admin-cli",
|
||||
});
|
||||
|
||||
try {
|
||||
await kcAdminClient.auth({
|
||||
username: KEYCLOAK_ADMIN_USER,
|
||||
password: KEYCLOAK_ADMIN_PASSWORD,
|
||||
grantType: 'password',
|
||||
clientId: 'admin-cli',
|
||||
});
|
||||
console.log("Authentication successful.");
|
||||
|
||||
console.log('Authentication successful.');
|
||||
kcAdminClient.setConfig({
|
||||
realmName: realm,
|
||||
});
|
||||
|
||||
// Set target realm
|
||||
kcAdminClient.setConfig({
|
||||
realmName: realm,
|
||||
});
|
||||
|
||||
// Find the client
|
||||
const clients = await kcAdminClient.clients.find({ clientId });
|
||||
if (clients.length === 0) {
|
||||
throw new Error(`Client '${clientId}' not found`);
|
||||
}
|
||||
const client = clients[0];
|
||||
|
||||
// Find the client scope
|
||||
const clientScopes = await kcAdminClient.clientScopes.find();
|
||||
const scope = clientScopes.find(s => s.name === scopeName);
|
||||
if (!scope) {
|
||||
throw new Error(`Client scope '${scopeName}' not found`);
|
||||
}
|
||||
|
||||
// Add scope to client as default scope
|
||||
await kcAdminClient.clients.addDefaultClientScope({
|
||||
id: client.id!,
|
||||
clientScopeId: scope.id!,
|
||||
});
|
||||
|
||||
console.log(`Client scope '${scopeName}' added to client '${clientId}' as default scope.`);
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error adding scope to client:', error);
|
||||
process.exit(1);
|
||||
const clients = await kcAdminClient.clients.find({ clientId });
|
||||
if (clients.length === 0) {
|
||||
throw new Error(`Client '${clientId}' not found`);
|
||||
}
|
||||
const client = clients[0];
|
||||
|
||||
const clientScopes = await kcAdminClient.clientScopes.find();
|
||||
const scope = clientScopes.find((s) => s.name === scopeName);
|
||||
if (!scope) {
|
||||
throw new Error(`Client scope '${scopeName}' not found`);
|
||||
}
|
||||
|
||||
await kcAdminClient.clients.addDefaultClientScope({
|
||||
id: client.id!,
|
||||
clientScopeId: scope.id!,
|
||||
});
|
||||
|
||||
console.log(`Client scope '${scopeName}' added to client '${clientId}' as default scope.`);
|
||||
} catch (error) {
|
||||
console.error("Error adding scope to client:", error);
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
main();
|
||||
main();
|
||||
|
||||
@@ -27,18 +27,14 @@ async function main() {
|
||||
invariant(clientId, "KEYCLOAK_CLIENT_ID is required");
|
||||
invariant(roleName, "KEYCLOAK_ROLE_NAME is required");
|
||||
|
||||
// Find the user
|
||||
const users = await kcAdminClient.users.find({ realm, username });
|
||||
|
||||
if (users.length === 0) {
|
||||
throw new Error(`User '${username}' not found in realm '${realm}'`);
|
||||
}
|
||||
|
||||
const user = users[0];
|
||||
|
||||
// Find the client
|
||||
const clients = await kcAdminClient.clients.find({ realm, clientId });
|
||||
|
||||
if (clients.length === 0) {
|
||||
throw new Error(`Client '${clientId}' not found in realm '${realm}'`);
|
||||
}
|
||||
@@ -60,35 +56,28 @@ async function main() {
|
||||
});
|
||||
console.error(
|
||||
`Available roles for client '${clientId}':`,
|
||||
allRoles.map((r) => r.name),
|
||||
allRoles.map((r) => r.name)
|
||||
);
|
||||
throw new Error(
|
||||
`Role '${roleName}' not found for client '${clientId}' in realm '${realm}'. Available roles: ${allRoles.map((r) => r.name).join(", ")}`,
|
||||
`Role '${roleName}' not found for client '${clientId}' in realm '${realm}'. Available roles: ${allRoles.map((r) => r.name).join(", ")}`
|
||||
);
|
||||
}
|
||||
|
||||
if (!role) {
|
||||
throw new Error(
|
||||
`Role '${roleName}' not found for client '${clientId}' in realm '${realm}'`,
|
||||
);
|
||||
throw new Error(`Role '${roleName}' not found for client '${clientId}' in realm '${realm}'`);
|
||||
}
|
||||
|
||||
// Check if user already has this role
|
||||
const existingRoles = await kcAdminClient.users.listClientRoleMappings({
|
||||
realm,
|
||||
id: user.id!,
|
||||
clientUniqueId: client.id!,
|
||||
});
|
||||
|
||||
const hasRole = existingRoles.some((r) => r.name === roleName);
|
||||
if (hasRole) {
|
||||
console.log(
|
||||
`User '${username}' already has role '${roleName}' for client '${clientId}'`,
|
||||
);
|
||||
console.log(`User '${username}' already has role '${roleName}' for client '${clientId}'`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Add role to user
|
||||
await kcAdminClient.users.addClientRoleMappings({
|
||||
realm,
|
||||
id: user.id!,
|
||||
@@ -102,7 +91,7 @@ async function main() {
|
||||
});
|
||||
|
||||
console.log(
|
||||
`✓ Role '${roleName}' assigned to user '${username}' for client '${clientId}' in realm '${realm}'`,
|
||||
`✓ Role '${roleName}' assigned to user '${username}' for client '${clientId}' in realm '${realm}'`
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -36,30 +36,26 @@ const main = async () => {
|
||||
|
||||
kcAdminClient.setConfig({ realmName });
|
||||
|
||||
// Find user
|
||||
const users = await kcAdminClient.users.find({ username });
|
||||
const user = users.find(u => u.username === 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);
|
||||
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);
|
||||
|
||||
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!,
|
||||
@@ -73,4 +69,4 @@ const main = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
main();
|
||||
main();
|
||||
|
||||
@@ -23,15 +23,11 @@ async function main() {
|
||||
invariant(clientId, "KEYCLOAK_CLIENT_ID is required");
|
||||
|
||||
try {
|
||||
// Find the client
|
||||
const clients = await kcAdminClient.clients.find({ realm, clientId });
|
||||
if (clients.length === 0) {
|
||||
throw new Error(`Client '${clientId}' not found in realm '${realm}'`);
|
||||
}
|
||||
|
||||
const client = clients[0];
|
||||
|
||||
// Get all protocol mappers with full details
|
||||
const mappers = await kcAdminClient.clients.listProtocolMappers({
|
||||
realm,
|
||||
id: client.id!,
|
||||
@@ -50,29 +46,25 @@ async function main() {
|
||||
}
|
||||
});
|
||||
|
||||
// Check client scope assignments
|
||||
console.log(`\n=== Client Scope Assignments ===`);
|
||||
|
||||
// Get default client scopes
|
||||
const defaultScopes = await kcAdminClient.clients.listDefaultClientScopes({
|
||||
realm,
|
||||
id: client.id!,
|
||||
});
|
||||
|
||||
console.log(`Default scopes: ${defaultScopes.map(s => s.name).join(', ')}`);
|
||||
console.log(`Default scopes: ${defaultScopes.map((s) => s.name).join(", ")}`);
|
||||
|
||||
// Get optional client scopes
|
||||
const optionalScopes = await kcAdminClient.clients.listOptionalClientScopes({
|
||||
realm,
|
||||
id: client.id!,
|
||||
});
|
||||
|
||||
console.log(`Optional scopes: ${optionalScopes.map(s => s.name).join(', ')}`);
|
||||
|
||||
console.log(`Optional scopes: ${optionalScopes.map((s) => s.name).join(", ")}`);
|
||||
} catch (error) {
|
||||
console.error(`Error: ${error}`);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
||||
main().catch(console.error);
|
||||
|
||||
@@ -23,15 +23,14 @@ async function main() {
|
||||
invariant(clientId, "KEYCLOAK_CLIENT_ID is required");
|
||||
|
||||
try {
|
||||
// Find the client by clientId
|
||||
const clients = await kcAdminClient.clients.find({ realm, clientId });
|
||||
|
||||
if (clients.length > 0) {
|
||||
console.log(`Client '${clientId}' exists in realm '${realm}'`);
|
||||
process.exit(0); // Success - client exists
|
||||
process.exit(0);
|
||||
} else {
|
||||
console.log(`Client '${clientId}' does not exist in realm '${realm}'`);
|
||||
process.exit(1); // Client doesn't exist
|
||||
process.exit(1);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Error checking client existence: ${error}`);
|
||||
@@ -39,4 +38,4 @@ async function main() {
|
||||
}
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
||||
main().catch(console.error);
|
||||
|
||||
@@ -24,16 +24,12 @@ async function main() {
|
||||
invariant(clientId, "KEYCLOAK_CLIENT_ID is required");
|
||||
invariant(roleName, "KEYCLOAK_ROLE_NAME is required");
|
||||
|
||||
// Find the client by clientId
|
||||
const clients = await kcAdminClient.clients.find({ realm, clientId });
|
||||
|
||||
if (clients.length === 0) {
|
||||
throw new Error(`Client '${clientId}' not found in realm '${realm}'`);
|
||||
}
|
||||
|
||||
const client = clients[0];
|
||||
|
||||
// Check if role already exists
|
||||
try {
|
||||
const existingRole = await kcAdminClient.clients.findRole({
|
||||
realm,
|
||||
@@ -49,17 +45,13 @@ async function main() {
|
||||
console.log(`Role '${roleName}' doesn't exist, creating it...`);
|
||||
}
|
||||
|
||||
// Create the client role
|
||||
await kcAdminClient.clients.createRole({
|
||||
realm,
|
||||
id: client.id!,
|
||||
name: roleName,
|
||||
});
|
||||
|
||||
console.log(
|
||||
`✓ Client role '${roleName}' created for client '${clientId}' in realm '${realm}'`,
|
||||
);
|
||||
console.log(`✓ Client role '${roleName}' created for client '${clientId}' in realm '${realm}'`);
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
||||
|
||||
|
||||
@@ -1,65 +1,63 @@
|
||||
#!/usr/bin/env tsx
|
||||
|
||||
import KcAdminClient from '@keycloak/keycloak-admin-client';
|
||||
import invariant from 'tiny-invariant';
|
||||
import KcAdminClient from "@keycloak/keycloak-admin-client";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
const main = async () => {
|
||||
const KEYCLOAK_HOST = process.env.KEYCLOAK_HOST;
|
||||
const KEYCLOAK_ADMIN_USER = process.env.KEYCLOAK_ADMIN_USER;
|
||||
const KEYCLOAK_ADMIN_PASSWORD = process.env.KEYCLOAK_ADMIN_PASSWORD;
|
||||
const realm = process.env.KEYCLOAK_REALM;
|
||||
const scopeName = process.env.SCOPE_NAME;
|
||||
const description = process.env.DESCRIPTION || '';
|
||||
const KEYCLOAK_HOST = process.env.KEYCLOAK_HOST;
|
||||
const KEYCLOAK_ADMIN_USER = process.env.KEYCLOAK_ADMIN_USER;
|
||||
const KEYCLOAK_ADMIN_PASSWORD = process.env.KEYCLOAK_ADMIN_PASSWORD;
|
||||
const realm = process.env.KEYCLOAK_REALM;
|
||||
const scopeName = process.env.SCOPE_NAME;
|
||||
const description = process.env.DESCRIPTION || "";
|
||||
|
||||
invariant(KEYCLOAK_HOST, 'KEYCLOAK_HOST environment variable is required');
|
||||
invariant(KEYCLOAK_ADMIN_USER, 'KEYCLOAK_ADMIN_USER environment variable is required');
|
||||
invariant(KEYCLOAK_ADMIN_PASSWORD, 'KEYCLOAK_ADMIN_PASSWORD environment variable is required');
|
||||
invariant(realm, 'KEYCLOAK_REALM environment variable is required');
|
||||
invariant(scopeName, 'SCOPE_NAME environment variable is required');
|
||||
invariant(KEYCLOAK_HOST, "KEYCLOAK_HOST environment variable is required");
|
||||
invariant(KEYCLOAK_ADMIN_USER, "KEYCLOAK_ADMIN_USER environment variable is required");
|
||||
invariant(KEYCLOAK_ADMIN_PASSWORD, "KEYCLOAK_ADMIN_PASSWORD environment variable is required");
|
||||
invariant(realm, "KEYCLOAK_REALM environment variable is required");
|
||||
invariant(scopeName, "SCOPE_NAME environment variable is required");
|
||||
|
||||
const kcAdminClient = new KcAdminClient({
|
||||
baseUrl: `https://${KEYCLOAK_HOST}`,
|
||||
realmName: 'master',
|
||||
const kcAdminClient = new KcAdminClient({
|
||||
baseUrl: `https://${KEYCLOAK_HOST}`,
|
||||
realmName: "master",
|
||||
});
|
||||
|
||||
try {
|
||||
await kcAdminClient.auth({
|
||||
username: KEYCLOAK_ADMIN_USER,
|
||||
password: KEYCLOAK_ADMIN_PASSWORD,
|
||||
grantType: "password",
|
||||
clientId: "admin-cli",
|
||||
});
|
||||
|
||||
try {
|
||||
await kcAdminClient.auth({
|
||||
username: KEYCLOAK_ADMIN_USER,
|
||||
password: KEYCLOAK_ADMIN_PASSWORD,
|
||||
grantType: 'password',
|
||||
clientId: 'admin-cli',
|
||||
});
|
||||
console.log("Authentication successful.");
|
||||
|
||||
console.log('Authentication successful.');
|
||||
kcAdminClient.setConfig({
|
||||
realmName: realm,
|
||||
});
|
||||
|
||||
// Set target realm
|
||||
kcAdminClient.setConfig({
|
||||
realmName: realm,
|
||||
});
|
||||
const existingScopes = await kcAdminClient.clientScopes.find();
|
||||
const existingScope = existingScopes.find((scope) => scope.name === scopeName);
|
||||
|
||||
// Check if scope already exists
|
||||
const existingScopes = await kcAdminClient.clientScopes.find();
|
||||
const existingScope = existingScopes.find(scope => scope.name === scopeName);
|
||||
|
||||
if (existingScope) {
|
||||
console.log(`Client scope '${scopeName}' already exists.`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Create client scope
|
||||
const result = await kcAdminClient.clientScopes.create({
|
||||
name: scopeName,
|
||||
description: description || `${scopeName} scope`,
|
||||
protocol: 'openid-connect',
|
||||
includeInTokenScope: true,
|
||||
});
|
||||
|
||||
console.log(`Client scope '${scopeName}' created successfully with ID: ${result.id}`);
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error creating client scope:', error);
|
||||
process.exit(1);
|
||||
if (existingScope) {
|
||||
console.log(`Client scope '${scopeName}' already exists.`);
|
||||
return;
|
||||
}
|
||||
|
||||
const result = await kcAdminClient.clientScopes.create({
|
||||
name: scopeName,
|
||||
description: description || `${scopeName} scope`,
|
||||
protocol: "openid-connect",
|
||||
attributes: {
|
||||
"include.in.token.scope": "true",
|
||||
},
|
||||
});
|
||||
|
||||
console.log(`Client scope '${scopeName}' created successfully with ID: ${result.id}`);
|
||||
} catch (error) {
|
||||
console.error("Error creating client scope:", error);
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
main();
|
||||
main();
|
||||
|
||||
@@ -22,7 +22,7 @@ const main = async () => {
|
||||
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 redirectUris = redirectUrl.split(",").map((url) => url.trim());
|
||||
|
||||
const sessionIdle = process.env.KEYCLOAK_CLIENT_SESSION_IDLE;
|
||||
const sessionMax = process.env.KEYCLOAK_CLIENT_SESSION_MAX;
|
||||
@@ -53,59 +53,61 @@ const main = async () => {
|
||||
return;
|
||||
}
|
||||
|
||||
const isPublicClient = !clientSecret || clientSecret === '';
|
||||
const isPublicClient = !clientSecret || clientSecret === "";
|
||||
const clientConfig: any = {
|
||||
clientId: clientId,
|
||||
secret: clientSecret,
|
||||
enabled: true,
|
||||
redirectUris: redirectUris,
|
||||
publicClient: isPublicClient,
|
||||
directAccessGrantsEnabled: directAccessGrants === 'true',
|
||||
directAccessGrantsEnabled: directAccessGrants === "true",
|
||||
};
|
||||
|
||||
// Configure PKCE based on environment variable
|
||||
// KEYCLOAK_CLIENT_PKCE_METHOD can be: 'S256', 'plain', or unset/empty (no PKCE)
|
||||
clientConfig.attributes = {};
|
||||
|
||||
if (pkceMethod && (pkceMethod === 'S256' || pkceMethod === 'plain')) {
|
||||
clientConfig.attributes['pkce.code.challenge.method'] = pkceMethod;
|
||||
if (pkceMethod && (pkceMethod === "S256" || pkceMethod === "plain")) {
|
||||
clientConfig.attributes["pkce.code.challenge.method"] = pkceMethod;
|
||||
console.log(`Setting PKCE Code Challenge Method to ${pkceMethod}`);
|
||||
} else if (pkceMethod && pkceMethod !== '') {
|
||||
console.warn(`Invalid PKCE method '${pkceMethod}'. Valid options: S256, plain, or empty for no PKCE`);
|
||||
console.log('Creating client without PKCE');
|
||||
} else if (pkceMethod && pkceMethod !== "") {
|
||||
console.warn(
|
||||
`Invalid PKCE method '${pkceMethod}'. Valid options: S256, plain, or empty for no PKCE`
|
||||
);
|
||||
console.log("Creating client without PKCE");
|
||||
} else {
|
||||
console.log('Creating client without PKCE');
|
||||
console.log("Creating client without PKCE");
|
||||
}
|
||||
|
||||
// Add session timeout settings if provided
|
||||
if (sessionIdle && sessionIdle !== '') {
|
||||
clientConfig.attributes['client.session.idle.timeout'] = sessionIdle;
|
||||
if (sessionIdle && sessionIdle !== "") {
|
||||
clientConfig.attributes["client.session.idle.timeout"] = sessionIdle;
|
||||
console.log(`Setting Client Session Idle Timeout: ${sessionIdle}`);
|
||||
}
|
||||
|
||||
if (sessionMax && sessionMax !== '') {
|
||||
clientConfig.attributes['client.session.max.lifespan'] = sessionMax;
|
||||
if (sessionMax && sessionMax !== "") {
|
||||
clientConfig.attributes["client.session.max.lifespan"] = sessionMax;
|
||||
console.log(`Setting Client Session Max Lifespan: ${sessionMax}`);
|
||||
}
|
||||
|
||||
// Add post logout redirect URIs if provided
|
||||
if (postLogoutRedirectUris && postLogoutRedirectUris !== '') {
|
||||
if (postLogoutRedirectUris && postLogoutRedirectUris !== "") {
|
||||
// Split comma-separated URIs and set as array in attributes using ## separator (Keycloak format)
|
||||
const postLogoutUris = postLogoutRedirectUris.split(',').map(uri => uri.trim());
|
||||
const postLogoutUris = postLogoutRedirectUris.split(",").map((uri) => uri.trim());
|
||||
clientConfig.attributes = clientConfig.attributes || {};
|
||||
clientConfig.attributes['post.logout.redirect.uris'] = postLogoutUris.join('##');
|
||||
console.log(`Setting Post Logout Redirect URIs: ${postLogoutUris.join(', ')}`);
|
||||
clientConfig.attributes["post.logout.redirect.uris"] = postLogoutUris.join("##");
|
||||
console.log(`Setting Post Logout Redirect URIs: ${postLogoutUris.join(", ")}`);
|
||||
}
|
||||
|
||||
// Add access token lifespan if provided
|
||||
if (accessTokenLifespan && accessTokenLifespan !== '') {
|
||||
if (accessTokenLifespan && accessTokenLifespan !== "") {
|
||||
clientConfig.attributes = clientConfig.attributes || {};
|
||||
clientConfig.attributes['access.token.lifespan'] = accessTokenLifespan;
|
||||
clientConfig.attributes["access.token.lifespan"] = accessTokenLifespan;
|
||||
console.log(`Setting Access Token Lifespan: ${accessTokenLifespan} seconds`);
|
||||
}
|
||||
|
||||
if (directAccessGrants === 'true') {
|
||||
console.log('Enabling Direct Access Grants (Resource Owner Password Credentials)');
|
||||
if (directAccessGrants === "true") {
|
||||
console.log("Enabling Direct Access Grants (Resource Owner Password Credentials)");
|
||||
}
|
||||
|
||||
const createdClient = await kcAdminClient.clients.create(clientConfig);
|
||||
|
||||
@@ -36,39 +36,41 @@ const main = async () => {
|
||||
|
||||
kcAdminClient.setConfig({ realmName });
|
||||
|
||||
// Check if group already exists
|
||||
const existingGroups = await kcAdminClient.groups.find({ search: groupName });
|
||||
const existingGroup = existingGroups.find(group => group.name === groupName);
|
||||
|
||||
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);
|
||||
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] } }),
|
||||
...(groupDescription && {
|
||||
attributes: { description: [groupDescription] },
|
||||
}),
|
||||
};
|
||||
|
||||
// Create group
|
||||
const group = parentGroupId
|
||||
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}'`);
|
||||
}
|
||||
@@ -79,4 +81,4 @@ const main = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
main();
|
||||
main();
|
||||
|
||||
@@ -17,7 +17,9 @@ const main = async () => {
|
||||
// Token lifespan settings (with defaults suitable for JupyterHub)
|
||||
const accessTokenLifespan = parseInt(process.env.ACCESS_TOKEN_LIFESPAN || "3600"); // 1 hour
|
||||
const refreshTokenLifespan = parseInt(process.env.REFRESH_TOKEN_LIFESPAN || "14400"); // 4 hours - changed from 30min
|
||||
const ssoSessionMaxLifespan = parseInt(process.env.SSO_SESSION_MAX_LIFESPAN || refreshTokenLifespan.toString()); // Use refreshTokenLifespan
|
||||
const ssoSessionMaxLifespan = parseInt(
|
||||
process.env.SSO_SESSION_MAX_LIFESPAN || refreshTokenLifespan.toString()
|
||||
); // Use refreshTokenLifespan
|
||||
const ssoSessionIdleTimeout = parseInt(process.env.SSO_SESSION_IDLE_TIMEOUT || "7200"); // 2 hours
|
||||
|
||||
const kcAdminClient = new KcAdminClient({
|
||||
@@ -59,10 +61,18 @@ const main = async () => {
|
||||
clientSessionIdleTimeout: Math.min(accessTokenLifespan, ssoSessionIdleTimeout),
|
||||
});
|
||||
console.log(`Realm '${realmName}' created successfully with token settings:`);
|
||||
console.log(` - Access Token Lifespan: ${accessTokenLifespan} seconds (${accessTokenLifespan/60} minutes)`);
|
||||
console.log(` - Refresh Token Lifespan: ${refreshTokenLifespan} seconds (${refreshTokenLifespan/60} minutes)`);
|
||||
console.log(` - SSO Session Max: ${ssoSessionMaxLifespan} seconds (${ssoSessionMaxLifespan/60} minutes)`);
|
||||
console.log(` - SSO Session Idle: ${ssoSessionIdleTimeout} seconds (${ssoSessionIdleTimeout/60} minutes)`);
|
||||
console.log(
|
||||
` - Access Token Lifespan: ${accessTokenLifespan} seconds (${accessTokenLifespan / 60} minutes)`
|
||||
);
|
||||
console.log(
|
||||
` - Refresh Token Lifespan: ${refreshTokenLifespan} seconds (${refreshTokenLifespan / 60} minutes)`
|
||||
);
|
||||
console.log(
|
||||
` - SSO Session Max: ${ssoSessionMaxLifespan} seconds (${ssoSessionMaxLifespan / 60} minutes)`
|
||||
);
|
||||
console.log(
|
||||
` - SSO Session Idle: ${ssoSessionIdleTimeout} seconds (${ssoSessionIdleTimeout / 60} minutes)`
|
||||
);
|
||||
} catch (error) {
|
||||
console.error("An error occurred:", error);
|
||||
// eslint-disable-next-line unicorn/no-process-exit
|
||||
|
||||
@@ -19,7 +19,7 @@ const main = async () => {
|
||||
|
||||
const kcAdminClient = new KcAdminClient({
|
||||
baseUrl: `https://${keycloakHost}`,
|
||||
realmName: 'master',
|
||||
realmName: "master",
|
||||
});
|
||||
|
||||
try {
|
||||
|
||||
@@ -33,36 +33,32 @@ const main = async () => {
|
||||
|
||||
kcAdminClient.setConfig({ realmName });
|
||||
|
||||
// Find group to delete
|
||||
const groups = await kcAdminClient.groups.find({ search: groupName });
|
||||
const group = groups.find(g => g.name === 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 && groupMembers.length > 0) {
|
||||
console.log(`Warning: Group '${groupName}' has ${groupMembers.length} members:`);
|
||||
groupMembers.forEach(member => {
|
||||
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! });
|
||||
const subGroups = await kcAdminClient.groups.listSubGroups({ parentId: group.id! });
|
||||
if (subGroups && subGroups.length > 0) {
|
||||
console.log(`Warning: Group '${groupName}' has ${subGroups.length} subgroups:`);
|
||||
subGroups.forEach(subGroup => {
|
||||
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`);
|
||||
@@ -73,4 +69,4 @@ const main = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
main();
|
||||
main();
|
||||
|
||||
@@ -15,7 +15,9 @@ const main = async () => {
|
||||
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.");
|
||||
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);
|
||||
}
|
||||
@@ -45,7 +47,6 @@ const main = async () => {
|
||||
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;
|
||||
@@ -58,4 +59,3 @@ const main = async () => {
|
||||
};
|
||||
|
||||
main();
|
||||
|
||||
|
||||
@@ -36,30 +36,26 @@ const main = async () => {
|
||||
|
||||
kcAdminClient.setConfig({ realmName });
|
||||
|
||||
// Find user
|
||||
const users = await kcAdminClient.users.find({ username });
|
||||
const user = users.find(u => u.username === 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);
|
||||
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);
|
||||
|
||||
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!,
|
||||
@@ -73,4 +69,4 @@ const main = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
main();
|
||||
main();
|
||||
|
||||
@@ -2,60 +2,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 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 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 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 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 clientId = process.env.KEYCLOAK_CLIENT_ID;
|
||||
invariant(clientId, "KEYCLOAK_CLIENT_ID environment variable is required");
|
||||
|
||||
const kcAdminClient = new KcAdminClient({
|
||||
baseUrl: `https://${keycloakHost}`,
|
||||
realmName: "master",
|
||||
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.");
|
||||
|
||||
try {
|
||||
await kcAdminClient.auth({
|
||||
username: adminUsername,
|
||||
password: adminPassword,
|
||||
grantType: "password",
|
||||
clientId: "admin-cli",
|
||||
});
|
||||
console.log("Authentication successful.");
|
||||
kcAdminClient.setConfig({ realmName });
|
||||
|
||||
kcAdminClient.setConfig({ realmName });
|
||||
|
||||
const existingClients = await kcAdminClient.clients.find({ clientId });
|
||||
if (existingClients.length === 0) {
|
||||
console.error(`Client '${clientId}' not found.`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const client = existingClients[0];
|
||||
invariant(client.id, "Client ID is missing");
|
||||
|
||||
await kcAdminClient.clients.update(
|
||||
{ id: client.id },
|
||||
{
|
||||
...client,
|
||||
serviceAccountsEnabled: true,
|
||||
authorizationServicesEnabled: false,
|
||||
}
|
||||
);
|
||||
|
||||
console.log(`Service Accounts enabled for client '${clientId}'`);
|
||||
} catch (error) {
|
||||
console.error("An error occurred:", error);
|
||||
process.exit(1);
|
||||
const existingClients = await kcAdminClient.clients.find({ clientId });
|
||||
if (existingClients.length === 0) {
|
||||
console.error(`Client '${clientId}' not found.`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const client = existingClients[0];
|
||||
invariant(client.id, "Client ID is missing");
|
||||
|
||||
await kcAdminClient.clients.update(
|
||||
{ id: client.id },
|
||||
{
|
||||
...client,
|
||||
serviceAccountsEnabled: true,
|
||||
authorizationServicesEnabled: false,
|
||||
}
|
||||
);
|
||||
|
||||
console.log(`Service Accounts enabled for client '${clientId}'`);
|
||||
} catch (error) {
|
||||
console.error("An error occurred:", error);
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
main();
|
||||
|
||||
@@ -23,15 +23,12 @@ async function main() {
|
||||
invariant(clientId, "KEYCLOAK_CLIENT_ID is required");
|
||||
|
||||
try {
|
||||
// Find the client
|
||||
const clients = await kcAdminClient.clients.find({ realm, clientId });
|
||||
if (clients.length === 0) {
|
||||
throw new Error(`Client '${clientId}' not found in realm '${realm}'`);
|
||||
}
|
||||
|
||||
const client = clients[0];
|
||||
|
||||
// Get full client details
|
||||
const clientDetails = await kcAdminClient.clients.findOne({
|
||||
realm,
|
||||
id: client.id!,
|
||||
@@ -39,17 +36,16 @@ async function main() {
|
||||
|
||||
console.log("=== Client Configuration ===");
|
||||
console.log(`Client ID: ${clientDetails?.clientId}`);
|
||||
console.log(`Access Type: ${clientDetails?.publicClient ? 'public' : 'confidential'}`);
|
||||
console.log(`Access Type: ${clientDetails?.publicClient ? "public" : "confidential"}`);
|
||||
console.log(`Client Authenticator: ${clientDetails?.clientAuthenticatorType}`);
|
||||
console.log(`Standard Flow Enabled: ${clientDetails?.standardFlowEnabled}`);
|
||||
console.log(`Direct Access Grants: ${clientDetails?.directAccessGrantsEnabled}`);
|
||||
console.log(`Service Accounts Enabled: ${clientDetails?.serviceAccountsEnabled}`);
|
||||
console.log(`Valid Redirect URIs: ${JSON.stringify(clientDetails?.redirectUris, null, 2)}`);
|
||||
console.log(`Base URL: ${clientDetails?.baseUrl || 'Not set'}`);
|
||||
console.log(`Root URL: ${clientDetails?.rootUrl || 'Not set'}`);
|
||||
console.log(`Base URL: ${clientDetails?.baseUrl || "Not set"}`);
|
||||
console.log(`Root URL: ${clientDetails?.rootUrl || "Not set"}`);
|
||||
console.log(`Web Origins: ${JSON.stringify(clientDetails?.webOrigins, null, 2)}`);
|
||||
|
||||
// Get client secret if confidential
|
||||
if (!clientDetails?.publicClient) {
|
||||
try {
|
||||
const clientSecret = await kcAdminClient.clients.getClientSecret({
|
||||
@@ -61,11 +57,10 @@ async function main() {
|
||||
console.log(`Client Secret: Error retrieving - ${error}`);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error(`Error retrieving client details: ${error}`);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
||||
main().catch(console.error);
|
||||
|
||||
88
keycloak/scripts/get-client-scope.ts
Executable file
88
keycloak/scripts/get-client-scope.ts
Executable file
@@ -0,0 +1,88 @@
|
||||
#!/usr/bin/env tsx
|
||||
|
||||
import KcAdminClient from "@keycloak/keycloak-admin-client";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
const main = async () => {
|
||||
const KEYCLOAK_HOST = process.env.KEYCLOAK_HOST;
|
||||
const KEYCLOAK_ADMIN_USER = process.env.KEYCLOAK_ADMIN_USER;
|
||||
const KEYCLOAK_ADMIN_PASSWORD = process.env.KEYCLOAK_ADMIN_PASSWORD;
|
||||
const realm = process.env.KEYCLOAK_REALM;
|
||||
const scopeName = process.env.SCOPE_NAME;
|
||||
|
||||
invariant(KEYCLOAK_HOST, "KEYCLOAK_HOST environment variable is required");
|
||||
invariant(KEYCLOAK_ADMIN_USER, "KEYCLOAK_ADMIN_USER environment variable is required");
|
||||
invariant(KEYCLOAK_ADMIN_PASSWORD, "KEYCLOAK_ADMIN_PASSWORD environment variable is required");
|
||||
invariant(realm, "KEYCLOAK_REALM environment variable is required");
|
||||
invariant(scopeName, "SCOPE_NAME environment variable is required");
|
||||
|
||||
const kcAdminClient = new KcAdminClient({
|
||||
baseUrl: `https://${KEYCLOAK_HOST}`,
|
||||
realmName: "master",
|
||||
});
|
||||
|
||||
try {
|
||||
await kcAdminClient.auth({
|
||||
username: KEYCLOAK_ADMIN_USER,
|
||||
password: KEYCLOAK_ADMIN_PASSWORD,
|
||||
grantType: "password",
|
||||
clientId: "admin-cli",
|
||||
});
|
||||
|
||||
kcAdminClient.setConfig({
|
||||
realmName: realm,
|
||||
});
|
||||
|
||||
const clientScopes = await kcAdminClient.clientScopes.find();
|
||||
const scope = clientScopes.find((s) => s.name === scopeName);
|
||||
|
||||
if (!scope) {
|
||||
console.error(`Client scope '${scopeName}' not found in realm '${realm}'.`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
invariant(scope.id, "Client scope ID is not set");
|
||||
|
||||
const protocolMappers = await kcAdminClient.clientScopes.listProtocolMappers({ id: scope.id });
|
||||
|
||||
console.log("\n=== Client Scope Details ===");
|
||||
console.log(`Name: ${scope.name}`);
|
||||
console.log(`ID: ${scope.id}`);
|
||||
console.log(`Description: ${scope.description || "(none)"}`);
|
||||
console.log(`Protocol: ${scope.protocol}`);
|
||||
console.log("\n=== Attributes ===");
|
||||
if (scope.attributes && Object.keys(scope.attributes).length > 0) {
|
||||
Object.entries(scope.attributes).forEach(([key, value]) => {
|
||||
console.log(` ${key}: ${value}`);
|
||||
});
|
||||
} else {
|
||||
console.log(" (none)");
|
||||
}
|
||||
|
||||
console.log("\n=== Protocol Mappers ===");
|
||||
if (protocolMappers.length > 0) {
|
||||
protocolMappers.forEach((mapper, index) => {
|
||||
console.log(`\nMapper ${index + 1}:`);
|
||||
console.log(` Name: ${mapper.name}`);
|
||||
console.log(` Protocol: ${mapper.protocol}`);
|
||||
console.log(` Protocol Mapper: ${mapper.protocolMapper}`);
|
||||
console.log(` Config:`);
|
||||
if (mapper.config && Object.keys(mapper.config).length > 0) {
|
||||
Object.entries(mapper.config).forEach(([key, value]) => {
|
||||
console.log(` ${key}: ${value}`);
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
console.log(" (none)");
|
||||
}
|
||||
|
||||
console.log("\n=== Raw JSON ===");
|
||||
console.log(JSON.stringify({ ...scope, protocolMappers }, null, 2));
|
||||
} catch (error) {
|
||||
console.error("Error retrieving client scope:", error);
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
main();
|
||||
@@ -23,26 +23,22 @@ async function main() {
|
||||
invariant(clientId, "KEYCLOAK_CLIENT_ID is required");
|
||||
|
||||
try {
|
||||
// Find the client
|
||||
const clients = await kcAdminClient.clients.find({ realm, clientId });
|
||||
if (clients.length === 0) {
|
||||
throw new Error(`Client '${clientId}' not found in realm '${realm}'`);
|
||||
}
|
||||
|
||||
const client = clients[0];
|
||||
|
||||
// Get client secret
|
||||
const clientSecret = await kcAdminClient.clients.getClientSecret({
|
||||
realm,
|
||||
id: client.id!,
|
||||
});
|
||||
|
||||
console.log(`Client '${clientId}' secret: ${clientSecret.value}`);
|
||||
|
||||
} catch (error) {
|
||||
console.error(`Error retrieving client secret: ${error}`);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
||||
main().catch(console.error);
|
||||
|
||||
@@ -44,8 +44,8 @@ const main = async () => {
|
||||
console.log(`=== Client Details: ${clientId} ===`);
|
||||
console.log(`ID: ${client.id}`);
|
||||
console.log(`Client ID: ${client.clientId}`);
|
||||
console.log(`Name: ${client.name || 'N/A'}`);
|
||||
console.log(`Description: ${client.description || 'N/A'}`);
|
||||
console.log(`Name: ${client.name || "N/A"}`);
|
||||
console.log(`Description: ${client.description || "N/A"}`);
|
||||
console.log(`Enabled: ${client.enabled}`);
|
||||
console.log(`Protocol: ${client.protocol}`);
|
||||
console.log(`Public Client: ${client.publicClient}`);
|
||||
@@ -108,7 +108,6 @@ const main = async () => {
|
||||
console.log("");
|
||||
}
|
||||
|
||||
// Get protocol mappers
|
||||
const protocolMappers = await kcAdminClient.clients.listProtocolMappers({ id: client.id! });
|
||||
if (protocolMappers.length > 0) {
|
||||
console.log("Protocol Mappers:");
|
||||
@@ -122,11 +121,10 @@ const main = async () => {
|
||||
});
|
||||
console.log("");
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error("An error occurred:", error);
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
main();
|
||||
main();
|
||||
|
||||
@@ -24,14 +24,12 @@ async function main() {
|
||||
invariant(username, "USERNAME is required");
|
||||
invariant(clientId, "KEYCLOAK_CLIENT_ID is required");
|
||||
|
||||
// Find the user
|
||||
const users = await kcAdminClient.users.find({ realm, username });
|
||||
if (users.length === 0) {
|
||||
throw new Error(`User '${username}' not found in realm '${realm}'`);
|
||||
}
|
||||
const user = users[0];
|
||||
|
||||
// Find the client
|
||||
const clients = await kcAdminClient.clients.find({ realm, clientId });
|
||||
if (clients.length === 0) {
|
||||
throw new Error(`Client '${clientId}' not found in realm '${realm}'`);
|
||||
@@ -39,16 +37,13 @@ async function main() {
|
||||
const client = clients[0];
|
||||
|
||||
try {
|
||||
// Get a token for this user (impersonation)
|
||||
console.log(`Getting token for user '${username}' with client '${clientId}'...`);
|
||||
|
||||
// Get client secret
|
||||
const clientSecret = await kcAdminClient.clients.getClientSecret({
|
||||
realm,
|
||||
id: client.id!,
|
||||
});
|
||||
|
||||
// Create a new client instance for the specific realm/client
|
||||
const userClient = new KcAdminClient({
|
||||
baseUrl: `https://${process.env.KEYCLOAK_HOST}`,
|
||||
realmName: realm,
|
||||
@@ -72,23 +67,21 @@ async function main() {
|
||||
console.log(`Protocol: ${client.protocol}`);
|
||||
console.log(`Public Client: ${client.publicClient}`);
|
||||
|
||||
// Get protocol mappers
|
||||
const mappers = await kcAdminClient.clients.listProtocolMappers({
|
||||
realm,
|
||||
id: client.id!,
|
||||
});
|
||||
|
||||
console.log("\n=== Protocol Mappers ===");
|
||||
mappers.forEach(mapper => {
|
||||
mappers.forEach((mapper) => {
|
||||
console.log(`- ${mapper.name} (${mapper.protocolMapper})`);
|
||||
if (mapper.config) {
|
||||
console.log(` Claim: ${mapper.config['claim.name'] || 'N/A'}`);
|
||||
console.log(` Access Token: ${mapper.config['access.token.claim'] || 'false'}`);
|
||||
console.log(` ID Token: ${mapper.config['id.token.claim'] || 'false'}`);
|
||||
console.log(` Claim: ${mapper.config["claim.name"] || "N/A"}`);
|
||||
console.log(` Access Token: ${mapper.config["access.token.claim"] || "false"}`);
|
||||
console.log(` ID Token: ${mapper.config["id.token.claim"] || "false"}`);
|
||||
}
|
||||
});
|
||||
|
||||
// Show user's client roles
|
||||
const clientRoles = await kcAdminClient.users.listClientRoleMappings({
|
||||
realm,
|
||||
id: user.id!,
|
||||
@@ -99,14 +92,13 @@ async function main() {
|
||||
if (clientRoles.length === 0) {
|
||||
console.log("No client roles assigned");
|
||||
} else {
|
||||
clientRoles.forEach(role => {
|
||||
clientRoles.forEach((role) => {
|
||||
console.log(`- ${role.name} (${role.id})`);
|
||||
});
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error(`Error: ${error}`);
|
||||
}
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
||||
main().catch(console.error);
|
||||
|
||||
@@ -39,18 +39,18 @@ const main = async () => {
|
||||
const status = client.enabled ? "Enabled" : "Disabled";
|
||||
const protocol = client.protocol || "unknown";
|
||||
|
||||
console.log(`${(index + 1).toString().padStart(2, ' ')}. ${client.clientId}`);
|
||||
console.log(`${(index + 1).toString().padStart(2, " ")}. ${client.clientId}`);
|
||||
console.log(` ID: ${client.id}`);
|
||||
console.log(` Type: ${clientType}`);
|
||||
console.log(` Protocol: ${protocol}`);
|
||||
console.log(` Status: ${status}`);
|
||||
|
||||
if (client.redirectUris && client.redirectUris.length > 0) {
|
||||
console.log(` Redirect URIs: ${client.redirectUris.join(', ')}`);
|
||||
console.log(` Redirect URIs: ${client.redirectUris.join(", ")}`);
|
||||
}
|
||||
|
||||
if (client.webOrigins && client.webOrigins.length > 0) {
|
||||
console.log(` Web Origins: ${client.webOrigins.join(', ')}`);
|
||||
console.log(` Web Origins: ${client.webOrigins.join(", ")}`);
|
||||
}
|
||||
|
||||
console.log("");
|
||||
@@ -61,4 +61,4 @@ const main = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
main();
|
||||
main();
|
||||
|
||||
@@ -24,18 +24,13 @@ async function main() {
|
||||
invariant(username, "USERNAME is required");
|
||||
invariant(clientId, "KEYCLOAK_CLIENT_ID is required");
|
||||
|
||||
// Find the user
|
||||
const users = await kcAdminClient.users.find({ realm, username });
|
||||
|
||||
if (users.length === 0) {
|
||||
throw new Error(`User '${username}' not found in realm '${realm}'`);
|
||||
}
|
||||
|
||||
const user = users[0];
|
||||
|
||||
// Find the client
|
||||
const clients = await kcAdminClient.clients.find({ realm, clientId });
|
||||
|
||||
if (clients.length === 0) {
|
||||
throw new Error(`Client '${clientId}' not found in realm '${realm}'`);
|
||||
}
|
||||
@@ -43,7 +38,6 @@ async function main() {
|
||||
const client = clients[0];
|
||||
|
||||
try {
|
||||
// Get user's client role mappings
|
||||
const clientRoles = await kcAdminClient.users.listClientRoleMappings({
|
||||
realm,
|
||||
id: user.id!,
|
||||
@@ -63,7 +57,6 @@ async function main() {
|
||||
});
|
||||
}
|
||||
|
||||
// Also show available roles for reference
|
||||
const availableRoles = await kcAdminClient.clients.listRoles({
|
||||
realm,
|
||||
id: client.id!,
|
||||
@@ -75,11 +68,10 @@ async function main() {
|
||||
const status = isAssigned ? "✓ assigned" : " available";
|
||||
console.log(` ${status}: ${role.name}`);
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error(`Error retrieving client roles: ${error}`);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
||||
main().catch(console.error);
|
||||
|
||||
@@ -26,32 +26,25 @@ async function main() {
|
||||
invariant(clientId, "KEYCLOAK_CLIENT_ID is required");
|
||||
invariant(roleName, "KEYCLOAK_ROLE_NAME is required");
|
||||
|
||||
// Find the user
|
||||
const users = await kcAdminClient.users.find({ realm, username });
|
||||
|
||||
if (users.length === 0) {
|
||||
throw new Error(`User '${username}' not found in realm '${realm}'`);
|
||||
}
|
||||
|
||||
const user = users[0];
|
||||
|
||||
// Find the client
|
||||
const clients = await kcAdminClient.clients.find({ realm, clientId });
|
||||
|
||||
if (clients.length === 0) {
|
||||
throw new Error(`Client '${clientId}' not found in realm '${realm}'`);
|
||||
}
|
||||
|
||||
const client = clients[0];
|
||||
|
||||
// Find the role
|
||||
const role = await kcAdminClient.clients.findRole({
|
||||
realm,
|
||||
id: client.id!,
|
||||
roleName,
|
||||
});
|
||||
|
||||
// Remove role from user
|
||||
await kcAdminClient.users.delClientRoleMappings({
|
||||
realm,
|
||||
id: user.id!,
|
||||
@@ -65,7 +58,7 @@ async function main() {
|
||||
});
|
||||
|
||||
console.log(
|
||||
`✓ Role '${roleName}' removed from user '${username}' for client '${clientId}' in realm '${realm}'`,
|
||||
`✓ Role '${roleName}' removed from user '${username}' for client '${clientId}' in realm '${realm}'`
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,77 +4,86 @@ import KcAdminClient from "@keycloak/keycloak-admin-client";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
const main = async () => {
|
||||
// Environment variables
|
||||
const keycloakHost = process.env.KEYCLOAK_HOST;
|
||||
const adminUser = process.env.KEYCLOAK_ADMIN_USER;
|
||||
const adminPassword = process.env.KEYCLOAK_ADMIN_PASSWORD;
|
||||
const realm = process.env.KEYCLOAK_REALM;
|
||||
const keycloakHost = process.env.KEYCLOAK_HOST;
|
||||
const adminUser = process.env.KEYCLOAK_ADMIN_USER;
|
||||
const adminPassword = process.env.KEYCLOAK_ADMIN_PASSWORD;
|
||||
const realm = process.env.KEYCLOAK_REALM;
|
||||
|
||||
invariant(keycloakHost, "KEYCLOAK_HOST is required");
|
||||
invariant(adminUser, "KEYCLOAK_ADMIN_USER is required");
|
||||
invariant(adminPassword, "KEYCLOAK_ADMIN_PASSWORD is required");
|
||||
invariant(realm, "KEYCLOAK_REALM is required");
|
||||
invariant(keycloakHost, "KEYCLOAK_HOST is required");
|
||||
invariant(adminUser, "KEYCLOAK_ADMIN_USER is required");
|
||||
invariant(adminPassword, "KEYCLOAK_ADMIN_PASSWORD is required");
|
||||
invariant(realm, "KEYCLOAK_REALM is required");
|
||||
|
||||
console.log(`Checking token settings for realm: ${realm}`);
|
||||
console.log(`Checking token settings for realm: ${realm}`);
|
||||
|
||||
// Initialize Keycloak admin client
|
||||
const kcAdminClient = new KcAdminClient({
|
||||
baseUrl: `https://${keycloakHost}`,
|
||||
realmName: "master",
|
||||
const kcAdminClient = new KcAdminClient({
|
||||
baseUrl: `https://${keycloakHost}`,
|
||||
realmName: "master",
|
||||
});
|
||||
|
||||
try {
|
||||
await kcAdminClient.auth({
|
||||
username: adminUser,
|
||||
password: adminPassword,
|
||||
grantType: "password",
|
||||
clientId: "admin-cli",
|
||||
});
|
||||
|
||||
try {
|
||||
// Authenticate
|
||||
await kcAdminClient.auth({
|
||||
username: adminUser,
|
||||
password: adminPassword,
|
||||
grantType: "password",
|
||||
clientId: "admin-cli",
|
||||
});
|
||||
console.log("✓ Authenticated with Keycloak admin");
|
||||
|
||||
console.log("✓ Authenticated with Keycloak admin");
|
||||
kcAdminClient.setConfig({ realmName: realm });
|
||||
|
||||
// Set the target realm
|
||||
kcAdminClient.setConfig({ realmName: realm });
|
||||
|
||||
// Get current realm settings
|
||||
const currentRealm = await kcAdminClient.realms.findOne({ realm });
|
||||
if (!currentRealm) {
|
||||
throw new Error(`Realm ${realm} not found`);
|
||||
}
|
||||
|
||||
console.log(`\n=== Current Token Settings for Realm: ${realm} ===`);
|
||||
console.log(`Access Token Lifespan: ${currentRealm.accessTokenLifespan || 'not set'} seconds (${(currentRealm.accessTokenLifespan || 0)/60} minutes)`);
|
||||
console.log(`Access Token Lifespan (Implicit): ${currentRealm.accessTokenLifespanForImplicitFlow || 'not set'} seconds`);
|
||||
console.log(`SSO Session Max Lifespan: ${currentRealm.ssoSessionMaxLifespan || 'not set'} seconds (${(currentRealm.ssoSessionMaxLifespan || 0)/60} minutes)`);
|
||||
console.log(`SSO Session Idle Timeout: ${currentRealm.ssoSessionIdleTimeout || 'not set'} seconds (${(currentRealm.ssoSessionIdleTimeout || 0)/60} minutes)`);
|
||||
console.log(`Client Session Max Lifespan: ${currentRealm.clientSessionMaxLifespan || 'not set'} seconds`);
|
||||
console.log(`Client Session Idle Timeout: ${currentRealm.clientSessionIdleTimeout || 'not set'} seconds`);
|
||||
console.log(`Offline Session Max Lifespan: ${currentRealm.offlineSessionMaxLifespan || 'not set'} seconds`);
|
||||
console.log(`Refresh Token Max Reuse: ${currentRealm.refreshTokenMaxReuse || 0}`);
|
||||
|
||||
// Also check specific client settings if JupyterHub client exists
|
||||
try {
|
||||
const clients = await kcAdminClient.clients.find({ clientId: 'jupyterhub' });
|
||||
if (clients.length > 0) {
|
||||
const jupyterhubClient = clients[0];
|
||||
console.log(`\n=== JupyterHub Client Settings ===`);
|
||||
console.log(`Client ID: ${jupyterhubClient.clientId}`);
|
||||
console.log(`Access Token Lifespan: ${jupyterhubClient.attributes?.['access.token.lifespan'] || 'inherit from realm'}`);
|
||||
}
|
||||
} catch (clientError) {
|
||||
console.log(`\n⚠️ Could not retrieve JupyterHub client settings: ${clientError}`);
|
||||
}
|
||||
|
||||
console.log(`\n=== Keycloak Default Values (for reference) ===`);
|
||||
console.log(`Default Access Token Lifespan: 300 seconds (5 minutes)`);
|
||||
console.log(`Default SSO Session Max: 36000 seconds (10 hours)`);
|
||||
console.log(`Default SSO Session Idle: 1800 seconds (30 minutes)`);
|
||||
|
||||
} catch (error) {
|
||||
console.error("✗ Failed to retrieve realm token settings:", error);
|
||||
process.exit(1);
|
||||
const currentRealm = await kcAdminClient.realms.findOne({ realm });
|
||||
if (!currentRealm) {
|
||||
throw new Error(`Realm ${realm} not found`);
|
||||
}
|
||||
|
||||
console.log(`\n=== Current Token Settings for Realm: ${realm} ===`);
|
||||
console.log(
|
||||
`Access Token Lifespan: ${currentRealm.accessTokenLifespan || "not set"} seconds (${(currentRealm.accessTokenLifespan || 0) / 60} minutes)`
|
||||
);
|
||||
console.log(
|
||||
`Access Token Lifespan (Implicit): ${currentRealm.accessTokenLifespanForImplicitFlow || "not set"} seconds`
|
||||
);
|
||||
console.log(
|
||||
`SSO Session Max Lifespan: ${currentRealm.ssoSessionMaxLifespan || "not set"} seconds (${(currentRealm.ssoSessionMaxLifespan || 0) / 60} minutes)`
|
||||
);
|
||||
console.log(
|
||||
`SSO Session Idle Timeout: ${currentRealm.ssoSessionIdleTimeout || "not set"} seconds (${(currentRealm.ssoSessionIdleTimeout || 0) / 60} minutes)`
|
||||
);
|
||||
console.log(
|
||||
`Client Session Max Lifespan: ${currentRealm.clientSessionMaxLifespan || "not set"} seconds`
|
||||
);
|
||||
console.log(
|
||||
`Client Session Idle Timeout: ${currentRealm.clientSessionIdleTimeout || "not set"} seconds`
|
||||
);
|
||||
console.log(
|
||||
`Offline Session Max Lifespan: ${currentRealm.offlineSessionMaxLifespan || "not set"} seconds`
|
||||
);
|
||||
console.log(`Refresh Token Max Reuse: ${currentRealm.refreshTokenMaxReuse || 0}`);
|
||||
|
||||
try {
|
||||
const clients = await kcAdminClient.clients.find({ clientId: "jupyterhub" });
|
||||
if (clients.length > 0) {
|
||||
const jupyterhubClient = clients[0];
|
||||
console.log(`\n=== JupyterHub Client Settings ===`);
|
||||
console.log(`Client ID: ${jupyterhubClient.clientId}`);
|
||||
console.log(
|
||||
`Access Token Lifespan: ${jupyterhubClient.attributes?.["access.token.lifespan"] || "inherit from realm"}`
|
||||
);
|
||||
}
|
||||
} catch (clientError) {
|
||||
console.log(`\n⚠️ Could not retrieve JupyterHub client settings: ${clientError}`);
|
||||
}
|
||||
|
||||
console.log(`\n=== Keycloak Default Values (for reference) ===`);
|
||||
console.log(`Default Access Token Lifespan: 300 seconds (5 minutes)`);
|
||||
console.log(`Default SSO Session Max: 36000 seconds (10 hours)`);
|
||||
console.log(`Default SSO Session Idle: 1800 seconds (30 minutes)`);
|
||||
} catch (error) {
|
||||
console.error("✗ Failed to retrieve realm token settings:", error);
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
main().catch(console.error);
|
||||
main().catch(console.error);
|
||||
|
||||
@@ -35,12 +35,10 @@ async function main() {
|
||||
clientId: "admin-cli",
|
||||
});
|
||||
|
||||
// Set realm to work with
|
||||
kcAdminClient.setConfig({
|
||||
realmName,
|
||||
});
|
||||
|
||||
// Find the client
|
||||
const clients = await kcAdminClient.clients.find({ clientId });
|
||||
if (clients.length === 0) {
|
||||
throw new Error(`Client '${clientId}' not found in realm '${realmName}'`);
|
||||
@@ -49,7 +47,6 @@ async function main() {
|
||||
const client = clients[0];
|
||||
const clientInternalId = client.id!;
|
||||
|
||||
// Find existing mapper
|
||||
const mappers = await kcAdminClient.clients.listProtocolMappers({ id: clientInternalId });
|
||||
const existingMapper = mappers.find((mapper) => mapper.name === mapperName);
|
||||
|
||||
@@ -61,7 +58,6 @@ async function main() {
|
||||
});
|
||||
}
|
||||
|
||||
// Create updated client roles protocol mapper
|
||||
await kcAdminClient.clients.addProtocolMapper(
|
||||
{ id: clientInternalId },
|
||||
{
|
||||
@@ -74,13 +70,15 @@ async function main() {
|
||||
"access.token.claim": "true",
|
||||
"claim.name": claimName,
|
||||
"jsonType.label": "String",
|
||||
"multivalued": "true",
|
||||
multivalued: "true",
|
||||
"usermodel.clientRoleMapping.clientId": clientId,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
console.log(`✓ Client roles mapper '${mapperName}' updated for client '${clientId}' in realm '${realmName}'`);
|
||||
console.log(
|
||||
`✓ Client roles mapper '${mapperName}' updated for client '${clientId}' in realm '${realmName}'`
|
||||
);
|
||||
console.log(` Claim name: ${claimName}`);
|
||||
console.log(` User Info: enabled`);
|
||||
console.log(` Access Token: enabled`);
|
||||
@@ -91,4 +89,4 @@ async function main() {
|
||||
}
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
||||
main().catch(console.error);
|
||||
|
||||
@@ -4,88 +4,84 @@ import KcAdminClient from "@keycloak/keycloak-admin-client";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
const main = async () => {
|
||||
// Environment variables
|
||||
const keycloakHost = process.env.KEYCLOAK_HOST;
|
||||
const adminUser = process.env.KEYCLOAK_ADMIN_USER;
|
||||
const adminPassword = process.env.KEYCLOAK_ADMIN_PASSWORD;
|
||||
const realm = process.env.KEYCLOAK_REALM;
|
||||
const accessTokenLifespan = parseInt(process.env.ACCESS_TOKEN_LIFESPAN || "3600");
|
||||
const refreshTokenLifespan = parseInt(process.env.REFRESH_TOKEN_LIFESPAN || "1800");
|
||||
const keycloakHost = process.env.KEYCLOAK_HOST;
|
||||
const adminUser = process.env.KEYCLOAK_ADMIN_USER;
|
||||
const adminPassword = process.env.KEYCLOAK_ADMIN_PASSWORD;
|
||||
const realm = process.env.KEYCLOAK_REALM;
|
||||
const accessTokenLifespan = parseInt(process.env.ACCESS_TOKEN_LIFESPAN || "3600");
|
||||
const refreshTokenLifespan = parseInt(process.env.REFRESH_TOKEN_LIFESPAN || "1800");
|
||||
|
||||
invariant(keycloakHost, "KEYCLOAK_HOST is required");
|
||||
invariant(adminUser, "KEYCLOAK_ADMIN_USER is required");
|
||||
invariant(adminPassword, "KEYCLOAK_ADMIN_PASSWORD is required");
|
||||
invariant(realm, "KEYCLOAK_REALM is required");
|
||||
invariant(keycloakHost, "KEYCLOAK_HOST is required");
|
||||
invariant(adminUser, "KEYCLOAK_ADMIN_USER is required");
|
||||
invariant(adminPassword, "KEYCLOAK_ADMIN_PASSWORD is required");
|
||||
invariant(realm, "KEYCLOAK_REALM is required");
|
||||
|
||||
console.log(`Updating token settings for realm: ${realm}`);
|
||||
console.log(`Access token lifespan: ${accessTokenLifespan} seconds (${accessTokenLifespan/60} minutes)`);
|
||||
console.log(`Refresh token lifespan: ${refreshTokenLifespan} seconds (${refreshTokenLifespan/60} minutes)`);
|
||||
console.log(`Updating token settings for realm: ${realm}`);
|
||||
console.log(
|
||||
`Access token lifespan: ${accessTokenLifespan} seconds (${accessTokenLifespan / 60} minutes)`
|
||||
);
|
||||
console.log(
|
||||
`Refresh token lifespan: ${refreshTokenLifespan} seconds (${refreshTokenLifespan / 60} minutes)`
|
||||
);
|
||||
|
||||
// Initialize Keycloak admin client
|
||||
const kcAdminClient = new KcAdminClient({
|
||||
baseUrl: `https://${keycloakHost}`,
|
||||
realmName: "master",
|
||||
const kcAdminClient = new KcAdminClient({
|
||||
baseUrl: `https://${keycloakHost}`,
|
||||
realmName: "master",
|
||||
});
|
||||
|
||||
try {
|
||||
await kcAdminClient.auth({
|
||||
username: adminUser,
|
||||
password: adminPassword,
|
||||
grantType: "password",
|
||||
clientId: "admin-cli",
|
||||
});
|
||||
|
||||
try {
|
||||
// Authenticate
|
||||
await kcAdminClient.auth({
|
||||
username: adminUser,
|
||||
password: adminPassword,
|
||||
grantType: "password",
|
||||
clientId: "admin-cli",
|
||||
});
|
||||
console.log("✓ Authenticated with Keycloak admin");
|
||||
|
||||
console.log("✓ Authenticated with Keycloak admin");
|
||||
kcAdminClient.setConfig({ realmName: realm });
|
||||
|
||||
// Set the target realm
|
||||
kcAdminClient.setConfig({ realmName: realm });
|
||||
|
||||
// Get current realm settings
|
||||
const currentRealm = await kcAdminClient.realms.findOne({ realm });
|
||||
if (!currentRealm) {
|
||||
throw new Error(`Realm ${realm} not found`);
|
||||
}
|
||||
|
||||
console.log(`Current settings:`);
|
||||
console.log(` - Access token lifespan: ${currentRealm.accessTokenLifespan} seconds`);
|
||||
console.log(` - Refresh token lifespan: ${currentRealm.ssoSessionMaxLifespan} seconds`);
|
||||
console.log(` - SSO session idle: ${currentRealm.ssoSessionIdleTimeout} seconds`);
|
||||
|
||||
// Update realm settings
|
||||
await kcAdminClient.realms.update(
|
||||
{ realm },
|
||||
{
|
||||
...currentRealm,
|
||||
// Access token settings
|
||||
accessTokenLifespan: accessTokenLifespan,
|
||||
accessTokenLifespanForImplicitFlow: accessTokenLifespan,
|
||||
// Refresh token settings
|
||||
refreshTokenMaxReuse: 0,
|
||||
ssoSessionMaxLifespan: refreshTokenLifespan,
|
||||
ssoSessionIdleTimeout: Math.min(refreshTokenLifespan, 1800), // Max 30 minutes idle
|
||||
// Other token settings
|
||||
offlineSessionMaxLifespan: refreshTokenLifespan * 2,
|
||||
offlineSessionMaxLifespanEnabled: true,
|
||||
// Client session settings
|
||||
clientSessionMaxLifespan: accessTokenLifespan,
|
||||
clientSessionIdleTimeout: Math.min(accessTokenLifespan, 1800),
|
||||
}
|
||||
);
|
||||
|
||||
console.log("✓ Realm token settings updated successfully");
|
||||
|
||||
// Verify the changes
|
||||
const updatedRealm = await kcAdminClient.realms.findOne({ realm });
|
||||
console.log(`Updated settings:`);
|
||||
console.log(` - Access token lifespan: ${updatedRealm?.accessTokenLifespan} seconds`);
|
||||
console.log(` - Refresh token lifespan: ${updatedRealm?.ssoSessionMaxLifespan} seconds`);
|
||||
console.log(` - SSO session idle: ${updatedRealm?.ssoSessionIdleTimeout} seconds`);
|
||||
|
||||
} catch (error) {
|
||||
console.error("✗ Failed to update realm token settings:", error);
|
||||
process.exit(1);
|
||||
const currentRealm = await kcAdminClient.realms.findOne({ realm });
|
||||
if (!currentRealm) {
|
||||
throw new Error(`Realm ${realm} not found`);
|
||||
}
|
||||
|
||||
console.log(`Current settings:`);
|
||||
console.log(` - Access token lifespan: ${currentRealm.accessTokenLifespan} seconds`);
|
||||
console.log(` - Refresh token lifespan: ${currentRealm.ssoSessionMaxLifespan} seconds`);
|
||||
console.log(` - SSO session idle: ${currentRealm.ssoSessionIdleTimeout} seconds`);
|
||||
|
||||
await kcAdminClient.realms.update(
|
||||
{ realm },
|
||||
{
|
||||
...currentRealm,
|
||||
// Access token settings
|
||||
accessTokenLifespan: accessTokenLifespan,
|
||||
accessTokenLifespanForImplicitFlow: accessTokenLifespan,
|
||||
// Refresh token settings
|
||||
refreshTokenMaxReuse: 0,
|
||||
ssoSessionMaxLifespan: refreshTokenLifespan,
|
||||
ssoSessionIdleTimeout: Math.min(refreshTokenLifespan, 1800), // Max 30 minutes idle
|
||||
// Other token settings
|
||||
offlineSessionMaxLifespan: refreshTokenLifespan * 2,
|
||||
offlineSessionMaxLifespanEnabled: true,
|
||||
// Client session settings
|
||||
clientSessionMaxLifespan: accessTokenLifespan,
|
||||
clientSessionIdleTimeout: Math.min(accessTokenLifespan, 1800),
|
||||
}
|
||||
);
|
||||
|
||||
console.log("✓ Realm token settings updated successfully");
|
||||
|
||||
const updatedRealm = await kcAdminClient.realms.findOne({ realm });
|
||||
console.log(`Updated settings:`);
|
||||
console.log(` - Access token lifespan: ${updatedRealm?.accessTokenLifespan} seconds`);
|
||||
console.log(` - Refresh token lifespan: ${updatedRealm?.ssoSessionMaxLifespan} seconds`);
|
||||
console.log(` - SSO session idle: ${updatedRealm?.ssoSessionIdleTimeout} seconds`);
|
||||
} catch (error) {
|
||||
console.error("✗ Failed to update realm token settings:", error);
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
main().catch(console.error);
|
||||
main().catch(console.error);
|
||||
|
||||
Reference in New Issue
Block a user