Help us improve
Share bugs, ideas, or general feedback.
From hudu
Manages Hudu asset passwords via /api/v1/asset_passwords: secure storage, retrieval, folders, access patterns, best practices, and audit logging.
npx claudepluginhub wyre-technology/msp-claude-plugins --plugin huduHow this skill is triggered — by the user, by Claude, or both
Slash command
/hudu:passwordsThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Passwords in Hudu (called "asset passwords" in the API) provide secure credential storage scoped to companies. They allow MSP technicians to store, organize, and retrieve credentials for client infrastructure, applications, and services. Password access can be restricted at the API key level, and all access is logged in Hudu's activity logs.
Manages IT Glue passwords: secure credential storage, categories, folders, embedded credentials, access patterns, audit logging, retrieval, and security best practices in MSP documentation.
Documents Hudu API patterns: x-api-key authentication, REST endpoints, UI/API naming differences, pagination, filtering, rate limiting, error handling, and permissions.
Implements Delinea Secret Server for PAM including vault configuration, role-based access policies, automated password rotation, session recording, and Active Directory/cloud integration.
Share bugs, ideas, or general feedback.
Passwords in Hudu (called "asset passwords" in the API) provide secure credential storage scoped to companies. They allow MSP technicians to store, organize, and retrieve credentials for client infrastructure, applications, and services. Password access can be restricted at the API key level, and all access is logged in Hudu's activity logs.
Critical API naming note: The Hudu UI calls these "Passwords," but the API endpoint is /api/v1/asset_passwords. Always use asset_passwords in API calls.
Passwords are organized by:
Company: Acme Corporation
+-- Passwords
+-- Infrastructure
| +-- Domain Admin - ACME
| +-- Local Admin - Servers
| +-- vCenter Admin
+-- Network
| +-- Firewall Admin
| +-- Switch Admin
| +-- WiFi Controller
+-- Applications
| +-- ERP Admin
| +-- CRM Admin
+-- Cloud Services
+-- Microsoft 365 Global Admin
+-- AWS Root Account
API keys in Hudu can be configured to allow or deny password access:
| Permission | Effect |
|---|---|
| Enabled | API key can read/write password values |
| Disabled | API key cannot access password values (403 Forbidden) |
This is configured per API key in Admin > API Keys.
Hudu logs all password access in the activity logs (/api/v1/activity_logs). This includes:
| Field | Type | Required | Description |
|---|---|---|---|
id | integer | System | Auto-generated unique identifier |
company_id | integer | Yes | Parent company |
name | string | Yes | Password display name |
username | string | No | Account username |
password | string | No | The actual password value |
url | string | No | Related URL/login page |
description | string | No | Additional notes |
password_type | string | No | Category/type label |
otp_secret | string | No | TOTP/2FA secret |
| Field | Type | Description |
|---|---|---|
password_folder_id | integer | Folder location |
password_folder_name | string | Folder name (read-only) |
| Field | Type | Description |
|---|---|---|
created_at | datetime | Creation timestamp |
updated_at | datetime | Last update timestamp |
slug | string | URL-friendly identifier |
url | string | Full URL in Hudu |
object_type | string | Always "AssetPassword" |
GET /api/v1/asset_passwords
x-api-key: YOUR_API_KEY
Content-Type: application/json
By Company:
GET /api/v1/asset_passwords?company_id=123
By Name:
GET /api/v1/asset_passwords?name=Domain Admin
With Pagination:
GET /api/v1/asset_passwords?company_id=123&page=1
Combined:
GET /api/v1/asset_passwords?company_id=123&name=admin
GET /api/v1/asset_passwords/789
x-api-key: YOUR_API_KEY
Response:
{
"asset_password": {
"id": 789,
"company_id": 123,
"company_name": "Acme Corporation",
"name": "Domain Admin - ACME",
"username": "administrator@acme.local",
"password": "SecureP@ssw0rd123!",
"url": "https://dc01.acme.local",
"description": "Primary domain administrator account.\nUse for:\n- Domain controller management\n- Group Policy changes\n- AD user management",
"password_type": "Administrative",
"password_folder_id": 45,
"password_folder_name": "Infrastructure",
"otp_secret": null,
"slug": "domain-admin-acme",
"created_at": "2024-01-15T10:30:00.000Z",
"updated_at": "2025-11-15T14:22:00.000Z",
"url": "https://your-company.huducloud.com/passwords/789"
}
}
IMPORTANT: The password value is returned in the response. Never expose password values in correlation summaries, logs, or output visible to unauthorized users.
POST /api/v1/asset_passwords
Content-Type: application/json
x-api-key: YOUR_API_KEY
{
"asset_password": {
"company_id": 123,
"name": "Domain Admin - ACME",
"username": "administrator@acme.local",
"password": "SecureP@ssw0rd123!",
"url": "https://dc01.acme.local",
"description": "Primary domain administrator account",
"password_type": "Administrative",
"password_folder_id": 45
}
}
PUT /api/v1/asset_passwords/789
Content-Type: application/json
x-api-key: YOUR_API_KEY
{
"asset_password": {
"password": "NewSecureP@ssw0rd456!",
"description": "Password rotated on 2026-02-15. Previous rotation: 2025-11-15."
}
}
DELETE /api/v1/asset_passwords/789
x-api-key: YOUR_API_KEY
Warning: Consider keeping passwords for audit purposes. Deletion requires DELETE permission on the API key.
By Name:
GET /api/v1/asset_passwords?name=Domain Admin
By Company:
GET /api/v1/asset_passwords?company_id=123
Combined:
GET /api/v1/asset_passwords?company_id=123&name=firewall
async function createSecurePassword(companyId, data) {
const password = await createAssetPassword({
company_id: companyId,
name: data.name,
username: data.username,
password: data.password,
url: data.url,
description: `Created: ${new Date().toLocaleDateString()}\nPurpose: ${data.purpose}`,
password_type: data.type,
password_folder_id: data.folderId
});
return password;
}
async function rotatePassword(passwordId, newPassword, reason) {
// Get current password info (for logging, not the value)
const current = await getAssetPassword(passwordId);
// Update with new password
const updated = await updateAssetPassword(passwordId, {
password: newPassword,
description: `${current.description || ''}\nRotated: ${new Date().toLocaleDateString()} - ${reason}`
});
return updated;
}
async function findPasswordsForServer(companyId, serverName) {
const passwords = await fetchAssetPasswords({ company_id: companyId });
return passwords.filter(p =>
p.name.toLowerCase().includes(serverName.toLowerCase()) ||
p.description?.toLowerCase().includes(serverName.toLowerCase()) ||
p.url?.toLowerCase().includes(serverName.toLowerCase())
);
}
async function findStalePasswords(companyId, daysOld = 90) {
const cutoffDate = new Date();
cutoffDate.setDate(cutoffDate.getDate() - daysOld);
const passwords = await fetchAssetPasswords({ company_id: companyId });
return passwords
.filter(p => new Date(p.updated_at) < cutoffDate)
.map(p => ({
id: p.id,
name: p.name,
username: p.username,
lastUpdated: p.updated_at,
daysSinceUpdate: Math.floor(
(new Date() - new Date(p.updated_at)) / (1000 * 60 * 60 * 24)
)
}));
}
async function generatePasswordReport(companyId) {
const passwords = await fetchAssetPasswords({ company_id: companyId });
const byType = {};
passwords.forEach(p => {
const type = p.password_type || 'Uncategorized';
if (!byType[type]) byType[type] = [];
byType[type].push({
name: p.name,
username: p.username,
url: p.url,
lastUpdated: p.updated_at
// NEVER include actual password values in reports
});
});
return byType;
}
CRITICAL: Never include actual password values in:
When displaying password information, always mask the actual value:
Password: Domain Admin - ACME
Username: administrator@acme.local
Password: **************
URL: https://dc01.acme.local
Monitor password access using Hudu's activity logs:
GET /api/v1/activity_logs?resource_type=AssetPassword&resource_id=789
| Code | Message | Resolution |
|---|---|---|
| 400 | Name can't be blank | Provide password name |
| 400 | Company is required | Include company_id |
| 401 | Invalid API key | Check HUDU_API_KEY |
| 403 | Password access denied | API key lacks password permission |
| 404 | Password not found | Verify password ID |
| 422 | Validation failed | Check required fields |
| Error | Cause | Fix |
|---|---|---|
| Name required | Missing name | Add name to request |
| Company required | No company_id | Include company_id |
| Access denied | API key lacks permission | Enable password access on API key |
| Invalid folder | Bad folder_id | Query password folders first |
async function safeGetPassword(passwordId) {
try {
return await getAssetPassword(passwordId);
} catch (error) {
if (error.status === 403) {
console.log('Password access denied. API key may lack password permission.');
return null;
}
if (error.status === 404) {
console.log('Password not found.');
return null;
}
throw error;
}
}