Monocloud management dotnet
Skill monocloud/agent-skills/plugins/monocloud/skills/monocloud-management-dotnet
Official MonoCloud Agent Skills repository.
npx -y skills add monocloud/agent-skills --skill monocloud-management-dotnetAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Use when calling the MonoCloud Management API from .NET — installing or configuring the `MonoCloud.Management` NuGet package, constructing `MonoCloudManagementClient` (direct or via DI with `AddMonoCloudManagementClient`), calling resource clients (`Users`, `Clients`, `Groups`, `Resources`, `Keys`, `Logs`, `NetworkZones`, `Options`, `Branding`, `TrustStores`) — including PKI/SPIFFE (mTLS) trust stores, external identity providers, network zones, and API access policies — reading `MonoCloudResponse<T>.Data` (and `PageData`/`PageModel` for paginated lists), catching `MonoCloudException` subclasses (`MonoCloudUnauthorizedException`, `MonoCloudForbiddenException`, `MonoCloudNotFoundException`, `MonoCloudIdentityValidationException`), or troubleshooting `MonoCloud:Management:Domain` / `MonoCloud:Management:ApiKey` / `Timeout` / 401 / 403 / 422 validation errors.
The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.
SKILL.md
22.8 KB, ~4.9k tokens by cl100k_base, as published. Nobody here has run it
MonoCloud Management .NET SDK (MonoCloud.Management)
Typed .NET SDK for the MonoCloud Management API. Use it to programmatically manage users, applications, groups, API resources, sign-in options, branding, logs, signing keys, network zones, and PKI/SPIFFE trust stores from .NET (Framework 4.6.2+, .NET Standard 2.0, or modern .NET).
Package identity — read this first
Use: the MonoCloud.Management NuGet package. Check *.csproj / packages.config before writing code — confirm the <PackageReference Include="MonoCloud.Management" ... /> is present and note its version.
This is not the same as:
MonoCloud.AspNetCore.Authentication/ any auth middleware (user-facing OIDC sign-in — outside this skill).MonoCloud.Management.Core— the internal core package thatMonoCloud.Managementdepends on. Do not add a project/package reference to it directly; app code depends only onMonoCloud.Management.
Stale-training-data guards — none of these exist in this SDK; do not emit them:
- There is no
MonoCloudManagementApi,ManagementApiClient, orApiCliententry type. The entry type isMonoCloudManagementClient. - Response bodies are read from
.Data, not.Result,.Body, or.Value. Status is.Status, not.StatusCode. - The SDK reads no environment variables of its own (no
MONOCLOUD_MANAGEMENT_*fallback). Config flows throughIConfiguration/ options only.
Installation
dotnet add package MonoCloud.Management
Install-Package MonoCloud.Management
Supported targets: .NET Framework 4.6.2+, .NET Standard 2.0, and any modern .NET 6.0+ that consumes netstandard2.0.
Authentication — Management API key
A Management API key (generated in the MonoCloud dashboard → Settings → API Keys) is required. It is tenant-scoped with full admin permissions — treat it like a root credential:
- Never check it into source control.
- Read it from
IConfiguration(appsettings.json+ environment variables / User Secrets / Key Vault / etc.).
The SDK authenticates by sending the key in the X-API-KEY request header. It sets BaseAddress to {Domain}/api/ under the hood.
Environment variables and configuration keys
The .NET SDK (v0.2.11) reads configuration from the MonoCloud:Management section of IConfiguration — it does not read process environment variables on its own. You can still surface env vars through the standard ASP.NET Core configuration mapping (double-underscore).
| Config key | Env-var form (ASP.NET Core) | Required | Purpose |
|---|---|---|---|
MonoCloud:Management:Domain | MonoCloud__Management__Domain | yes | Tenant URL, e.g. https://acme.us.monocloud.com |
MonoCloud:Management:ApiKey | MonoCloud__Management__ApiKey | yes | Management API key |
MonoCloud:Management:Timeout | MonoCloud__Management__Timeout | no | Request timeout in seconds (default 10) |
Domain is sanitized on construction: a missing https:// prefix is added and a trailing / is stripped. Store the API key in User Secrets locally (dotnet user-secrets set "MonoCloud:Management:ApiKey" "...") and a secret manager in production — never in a shipped appsettings.json.
Quick start — DI (recommended)
appsettings.Development.json (API key comes from User Secrets, not this file):
{
"MonoCloud": {
"Management": {
"Domain": "https://your-tenant.us.monocloud.com",
"Timeout": "30"
}
}
}
Program.cs:
using MonoCloud.Management;
var builder = WebApplication.CreateBuilder(args);
// Reads the MonoCloud:Management section from IConfiguration.
builder.Services.AddMonoCloudManagementClient(builder.Configuration);
var app = builder.Build();
app.MapGet("/users", async (MonoCloudManagementClient management) =>
{
var response = await management.Users.GetAllUsersAsync(page: 1, size: 25);
return Results.Ok(response.Data); // response.Data is List<UserSummary>
});
app.Run();
Inject MonoCloudManagementClient wherever you need it. AddMonoCloudManagementClient registers it as transient, backed by a named IHttpClientFactory client ("MonoCloudManagementClient"), so pooling/retries/policies layer cleanly on top.
Mixing DI options with code
AddMonoCloudManagementClient also accepts an Action<MonoCloudManagementOptions> — alone, or alongside IConfiguration. When both are supplied, the options action wins for any value it sets. Registration throws ArgumentNullException if Domain or ApiKey is empty after merging.
builder.Services.AddMonoCloudManagementClient(builder.Configuration, options =>
{
options.ApiKey = builder.Configuration["Secrets:MonoCloudApiKey"];
options.Timeout = TimeSpan.FromSeconds(60);
});
MonoCloudManagementOptions is { string? Domain; string? ApiKey; TimeSpan? Timeout; }.
Quick start — direct construction
For console apps, background workers, or scenarios without DI:
using MonoCloud.Management;
using MonoCloud.Management.Core.Base; // MonoCloudConfig
var config = new MonoCloudConfig(
domain: "https://your-tenant.us.monocloud.com",
apiKey: "your-management-api-key",
timeout: TimeSpan.FromSeconds(30) // optional; defaults to 10s
);
var management = new MonoCloudManagementClient(config);
var response = await management.Users.GetAllUsersAsync(1, 25);
MonoCloudConfig just carries Domain, ApiKey, and Timeout — it does not validate on its own. The non-empty Domain/ApiKey check runs when the client is built (in MonoCloudClientBase), so a bad config throws MonoCloudException (Tenant Domain is required / API Key is required) at new MonoCloudManagementClient(config), not at new MonoCloudConfig(...).
MonoCloudManagementClient also accepts a pre-built HttpClient — useful for integration tests and custom HTTP pipelines (see DI registration and HTTP-layer replacement):
var http = new HttpClient { BaseAddress = new Uri("https://example.com/api/") };
http.DefaultRequestHeaders.Add("X-API-KEY", "test-key");
var management = new MonoCloudManagementClient(http);
Client surface
MonoCloudManagementClient exposes 10 resource-client properties:
| Property | Resource area | Backing type |
|---|---|---|
.Users | Users: CRUD, identifiers, passwords, passkeys, claims, sessions, grants | UsersClient |
.Clients | OAuth/OIDC applications (operates on the Application model) | ClientsClient |
.Groups | Groups: CRUD | GroupsClient |
.Resources | API resources, API scopes, API access policies, scopes, claim resources | ResourcesClient |
.Keys | Signing key material: list, rotate, revoke | KeysClient |
.Logs | Audit / event logs: list, find | LogsClient |
.NetworkZones | IP + regional network zones (ScaleX for create/patch) | NetworkZonesClient |
.Options | Tenant options: authentication, communication, sign-up custom fields, external identity providers | OptionsClient |
.Branding | Branding options for pages, emails, SMS | BrandingClient |
.TrustStores | PKI (mTLS) + SPIFFE trust stores, revocations, bans | TrustStoresClient |
All resource-client classes live in namespace MonoCloud.Management.Clients and derive from MonoCloudClientBase. Every method is PascalCase, ends in Async, and takes a trailing CancellationToken cancellationToken = default. See references/api-surface.md for the full, per-method index (signatures verbatim, including subscription-tier notes).
Naming quirk —
Clientsoperates onApplication. The.Clientsaccessor /ClientsClientmanages theApplicationresource:GetAllApplicationsAsync,CreateApplicationAsync,PatchApplicationRequest, etc. Path params are namedclientId(astring), but there is noClientmodel — do not expect one.
Response shape
Every method returns one of three envelopes from namespace MonoCloud.Management.Core.Base:
public class MonoCloudResponse
{
public int Status { get; } // HTTP status
public IDictionary<string, IEnumerable<string>> Headers { get; } // multi-valued
}
public class MonoCloudResponse<T> : MonoCloudResponse
{
public T Data { get; } // deserialized body
}
// Paginated list variant adds .PageData
public class MonoCloudResponse<T, TPage> : MonoCloudResponse<T> where TPage : PageModel
{
public TPage PageData { get; } // TPage is always PageModel; zero-valued if the server omits x-pagination
}
public class PageModel // namespace MonoCloud.Management.Core.Helpers
{
public int PageSize { get; set; }
public int CurrentPage { get; set; }
public int TotalCount { get; set; }
public bool HasPrevious { get; set; }
public bool HasNext { get; set; }
}
- The body property is
Data(notResult); the status property isStatus(notStatusCode). - Void-return operations (Delete / Remove / Revoke / Rotate / ban-removal /
AssignGroupToApplicationAsync) return the bareMonoCloudResponse— there is no.Data; read.Status/.Headers. - A few list endpoints return
MonoCloudResponse<List<T>>(noPageData):GetAllApplicationSecretsAsync,GetAllApiResourceSecretsAsync,GetAllSignUpCustomFieldsAsync,GetAllPkiBannedCertificatesAsync,GetAllSpiffeBannedSvidsAsync. Most other list endpoints are paginated (MonoCloudResponse<List<T>, PageModel>).
Pagination
Pagination metadata arrives in the x-pagination response header and lands in .PageData. Idiomatic drain loop:
async IAsyncEnumerable<UserSummary> EachUserAsync(
MonoCloudManagementClient management,
[EnumeratorCancellation] CancellationToken ct = default)
{
var page = 1;
while (true)
{
var response = await management.Users.GetAllUsersAsync(page, size: 100, cancellationToken: ct);
foreach (var u in response.Data) yield return u;
if (!response.PageData.HasNext) yield break;
page++;
}
}
Paginated list methods share the (int? page = 1, int? size = 10, string? filter = default, string? sort = default, CancellationToken) shape:
page— 1-indexed (defaults to 1).size— items per page (defaults to 10).filter— Lucene-style expression (per-endpoint; see the API docs).sort—"<field>:<1|-1>"(1 ascending, -1 descending).
Common operations
Create a user
var created = await management.Users.CreateUserAsync(new CreateUserRequest
{
Email = "[email protected]",
EmailVerified = true,
Name = "Alice Example",
});
var userId = created.Data.UserId; // the identifier field is UserId (string), not Id
Look up a user, handling not-found
try
{
var response = await management.Users.FindUserByIdAsync(userId);
return response.Data; // User
}
catch (MonoCloudNotFoundException)
{
return null;
}
Patch claims / metadata (partial update)
await management.Users.PatchPrivateDataAsync(userId, new UpdatePrivateDataRequest
{
PrivateData = new Dictionary<string, object> { ["onboarded"] = true, ["plan"] = "pro" }
});
Patch*Request bodies use Optional<T> per property — only fields you explicitly assign are serialized, so PATCH is a true partial update. Resource identifiers are path-only and never appear in the patch body (they cannot be changed).
Disable a user
await management.Users.DisableUserAsync(userId, new DisableUserRequest { RevokeSessions = true });
List applications
// The accessor is .Clients, but the methods and models talk about Application*.
var apps = await management.Clients.GetAllApplicationsAsync(page: 1, size: 50);
foreach (var app in apps.Data) { /* app is Application */ }
Read audit logs
var logs = await management.Logs.GetAllLogsAsync(page: 1, size: 20, sort: "created:-1");
foreach (var log in logs.Data) { /* log is Log */ }
var one = await management.Logs.FindLogByIdAsync(logId); // logId is a Guid
Errors
Every non-2xx response throws a typed exception. All derive from MonoCloudException (namespace MonoCloud.Management.Core.Exception); HTTP-status exceptions derive from MonoCloudRequestException, which exposes ProblemDetails? Response.
| Class | Thrown for |
|---|---|
MonoCloudBadRequestException | 400 |
MonoCloudUnauthorizedException | 401 — bad/missing X-API-KEY |
MonoCloudPaymentRequiredException | 402 — subscription/billing required |
MonoCloudForbiddenException | 403 — feature not on the current plan / insufficient tier |
MonoCloudNotFoundException | 404 |
MonoCloudConflictException | 409 |
MonoCloudIdentityValidationException | 422 (identity validation) — .Errors is IEnumerable<IdentityError> |
MonoCloudKeyValidationException | 422 (field validation) — .Errors is IDictionary<string, string[]> |
MonoCloudModelStateException | 422 (fallback / non-problem+json body) |
MonoCloudResourceExhaustedException | 429 — rate limited |
MonoCloudServerException | 5xx |
MonoCloudRequestException | base for all HTTP-status exceptions — exposes .Response (ProblemDetails?) |
MonoCloudException | base (Exception) — also thrown for config/transport/deserialization failures |
MonoCloudException has no StatusCode property. Branch on the subclass, or read (ex as MonoCloudRequestException)?.Response?.Status for the problem-details status.
try
{
await management.Users.CreateUserAsync(req);
}
catch (MonoCloudConflictException)
{
return Results.Conflict();
}
catch (MonoCloudIdentityValidationException ex)
{
return Results.UnprocessableEntity(ex.Errors); // IEnumerable<IdentityError>
}
catch (MonoCloudRequestException ex)
{
logger.LogError(ex, "MonoCloud Management API call failed: {Status} {Title}",
ex.Response?.Status, ex.Response?.Title);
throw;
}
Subscription tiers
Some endpoints require a paid tier; the server returns 403 (MonoCloudForbiddenException) or 402 (MonoCloudPaymentRequiredException) when the tier is insufficient.
| Tier | Gated operations |
|---|---|
| Pro | Groups.CreateGroupAsync beyond two groups; Users session methods (GetAllUserSessionsAsync, FindUserSessionAsync, RevokeUserSessionAsync); Users.GetAllUserClientGrantsAsync |
| Secure+ | Users consent/token reads (GetAllUserConsentsAsync, GetAllReferenceTokensAsync, GetAllRefreshTokensAsync, GetAllAuthorizationCodesAsync) and the matching Revoke* methods; the EnableConsent field on Application requests |
| ScaleX | NetworkZones create/patch (CreateIpNetworkZoneAsync, PatchIpNetworkZoneAsync, CreateRegionalNetworkZoneAsync, PatchRegionalNetworkZoneAsync); Clients.AssignGroupToApplicationAsync / RemoveGroupFromApplicationAsync; Resources.CreateApiResourceSecretAsync |
Several request fields (e.g. EnableConsent, PAR/JAR, back-channel logout, extended refresh-token lifetimes) also carry tier gates even on otherwise-free endpoints. The <note>…subscription…</note> XML comments in the SDK source are the source of truth — see references/api-surface.md.
DI registration and HTTP-layer replacement
AddMonoCloudManagementClient (static class MonoCloudManagementServiceExtensions, namespace MonoCloud.Management) has three overloads, all returning IServiceCollection:
AddMonoCloudManagementClient(IConfiguration configuration)— reads theMonoCloud:Managementsection.AddMonoCloudManagementClient(Action<MonoCloudManagementOptions> options)— configure in code.AddMonoCloudManagementClient(IConfiguration? configuration, Action<MonoCloudManagementOptions>? options)— both; options override configuration.
It registers a named HttpClient ("MonoCloudManagementClient") with BaseAddress = {Domain}/api/, Timeout = config.Timeout, and the X-API-KEY default header, then registers MonoCloudManagementClient as transient over IHttpClientFactory.
Bring-your-own HttpClient. The MonoCloudManagementClient(HttpClient httpClient) constructor bypasses MonoCloudConfig, so you own the full pipeline (custom HttpMessageHandler, Polly policies, proxies, mTLS, test doubles). You must set BaseAddress (ending in /api/) and the X-API-KEY header yourself.
Common pitfalls
- Hardcoding the API key in
appsettings.json. Use User Secrets for dev and a secret manager (Azure Key Vault, AWS Secrets Manager) in production. - Expecting env-var fallback. Unlike the JS SDK, this SDK reads no
MONOCLOUD_MANAGEMENT_*env vars itself. Feed values throughIConfiguration(which can bind env vars via theMonoCloud__Management__*mapping) or the options action. - Trailing
/apionDomain. Pass the bare tenant URL — the SDK appends/api/. - Milliseconds vs seconds for timeout.
MonoCloud:Management:Timeoutis seconds (mapped toTimeSpan.FromSeconds/TotalSeconds). The default is10— long-running admin calls may need it raised. - Sending immutable identifiers on
Patch…requests. Identifier fields were removed from PATCH request models in 0.2.6 (AudiencefromPatchApiResourceRequest;NamefromPatchApiScopeRequest,PatchScopeRequest,PatchClaimResourceRequest). The C# property is gone — old code that set it won't compile. - Parameter-order gotchas in
ResourcesClient.FindApiResourceSecretByIdAsync(secretId, apiId, …)and the API-scope find/patch/delete methods take(scopeId, apiId, …)— the scope/secret id comes beforeapiId. ButDeleteApiResourceSecretAsync(apiId, secretId, …)and the create methods takeapiIdfirst. Copy the signatures verbatim fromreferences/api-surface.md. Guidvsstringids. Group ids and user identifier ids areGuid(groupId,identifierId,logId); user / application / resource / zone / trust-store / session ids arestring.- Reading
response.Result/ex.StatusCode. The body is.Data, the status is.Status;MonoCloudExceptionhas noStatusCode— branch on the subclass or read(ex as MonoCloudRequestException)?.Response?.Status. new-ingMonoCloudManagementClientper request under DI. It's already registered transient overIHttpClientFactory— inject it, don't construct it in controllers.- Referencing
MonoCloud.Management.Coredirectly. The core types (MonoCloudConfig,MonoCloudResponse<T>, exceptions) come transitively withMonoCloud.Management; don't add a separate package reference. - Using ScaleX/Secure+ features without the tier.
NetworkZonescreate/patch, application↔group assignment, API-resource-secret creation, and consent/token endpoints throwMonoCloudForbiddenException(or 402) on lower plans. Verify the tenant's plan before wiring them into production.
Onboarding checklist
dotnet add package MonoCloud.Management.- Create a Management API key in the MonoCloud dashboard.
- Set
MonoCloud:Management:Domain(inappsettings.json/config) andMonoCloud:Management:ApiKey(in User Secrets / Key Vault / env var). Program.cs:builder.Services.AddMonoCloudManagementClient(builder.Configuration).- Inject
MonoCloudManagementClientand call resource clients (management.Users.GetAllUsersAsync(...), etc.). - Read results from
response.Data(andresponse.PageDatafor paginated lists). - Wrap calls in
try/catchagainst the specificMonoCloudExceptionsubclass(es) you handle. - Run
node scripts/verify.js /path/to/projectto confirm package installation + config.
Deeper reference
references/api-surface.md— every resource client and method, with verbatim signatures, response types, and subscription-tier notes.references/troubleshooting.md— symptom → cause → fix for the common failure modes (401/403, missingDomain/ApiKeyat startup, secret leaks, hand-newed clients vs DI, genericcatch (Exception), single-page reads).