Policies
A policy is a JSON document describing one or more Allow / Deny statements. Attach a policy to a user, group, role, or service account and that principal can (or can't) perform the listed actions on the listed resources.
Huudis follows AWS IAM's evaluation rules with a few simplifications:
- Default is deny. A principal must have at least one matching
Allowto perform an action. - Explicit
Denywins over anyAllow. UseDenyto enforce hard guardrails (e.g. "never touch production-billing"). - No "policy version" branching — updates increment a
versioncounter on the row but only the latest version is live.
All endpoints require a bearer admin JWT — see Authentication.
Endpoints
| Method | Path | Purpose |
|---|---|---|
POST |
/v1/iam/policies |
Create a custom policy |
GET |
/v1/iam/policies |
List custom + visible system policies |
GET |
/v1/iam/policies/:id |
Retrieve one |
PATCH |
/v1/iam/policies/:id |
Update description and/or document |
DELETE |
/v1/iam/policies/:id |
Delete a custom policy |
System policies (the Huudis*, Plugipay*, etc. that ship with the product) are read-only — PATCH and DELETE return 403 FORBIDDEN.
Create a policy
POST /v1/iam/policies
Request body
| Field | Type | Required | Description |
|---|---|---|---|
name |
string (1–120) | yes | Policy name. Unique per workspace. |
description |
string (≤500) | no | Operator note. |
document |
object | yes | The policy JSON. Schema below. |
Response — 201 Created. The full policy with version: 1.
List policies
GET /v1/iam/policies
Returns:
- Custom policies — ones the caller's workspace created.
- System policies — canned policies (e.g.
HuudisReadOnly,PlugipayAdmin) but only for services the workspace has opted into via Services. A workspace that hasn't enabled Plugipay won't seePlugipay*policies.
Sorted with system policies first, then custom newest-first.
Update a policy
PATCH /v1/iam/policies/:id
Request body
| Field | Description |
|---|---|
description |
Change the description. |
document |
Replace the policy JSON. Increments the version counter. |
System policies cannot be updated. 403 FORBIDDEN if you try.
Delete a policy
DELETE /v1/iam/policies/:id
Hard-deletes a custom policy. All attachments cascade-delete — the principals lose those permissions immediately. System policies return 403.
204 No Content.
The policy object
| Field | Type | Description |
|---|---|---|
id |
string (pol_…) |
Stable ID. |
accountId |
string | null | Owning workspace. null for system policies. |
scope |
custom | system |
System policies ship with Huudis and aren't editable. |
service |
string | null | For system policies, the service this policy is associated with (huudis, plugipay, etc.). null for legacy untagged. |
name |
string | Display name. Unique per workspace (or globally for system). |
description |
string | null | |
document |
object | The policy JSON. See Document schema. |
version |
integer | Bumps on every PATCH document=…. Starts at 1. |
createdAt |
ISO 8601 |
Document schema
{
"Version": "2026-01-01",
"Statement": [
{
"Sid": "ReadOnlyAudit",
"Effect": "Allow",
"Action": ["huudis:audit:read", "huudis:audit:export"],
"Resource": "*"
},
{
"Sid": "DenyDuringFreeze",
"Effect": "Deny",
"Action": "huudis:*:write",
"Resource": "*",
"Condition": {
"DateGreaterThan": { "forjio:CurrentTime": "2026-05-31T23:59:59Z" },
"DateLessThan": { "forjio:CurrentTime": "2026-06-02T00:00:00Z" }
}
}
]
}
Recognised top-level keys:
Version— a date-versioned string. Currently informational only.Statement— an array. Order doesn't matter; the evaluator scans all statements.
Per-statement keys:
| Key | Required | Description |
|---|---|---|
Sid |
no | Optional statement identifier. Echoed in the authz check response so you can pinpoint which statement matched. |
Effect |
yes | Allow or Deny. |
Action / NotAction |
one of | Action(s) to match. String or array. Supports trailing-* wildcards (huudis:*:write). |
Resource / NotResource |
one of | Resource ARN(s). Supports wildcards. |
Condition |
no | Map of condition-operator → key → expected. Same shape as AWS. |
Condition operators recognised: StringEquals, StringNotEquals, StringLike, Bool, DateGreaterThan, DateLessThan, IpAddress, NotIpAddress, NumericEquals, NumericLessThan, NumericGreaterThan.
Action namespace
Actions use the pattern <service>:<resource>:<verb>. Examples:
| Action | What it allows |
|---|---|
huudis:users:read |
List/read workspace members |
huudis:users:write |
Add/modify/remove members |
huudis:oidc_clients:* |
Anything against OIDC clients |
huudis:audit:read |
Read the audit log |
huudis:audit:export |
Bulk-export the audit log |
huudis:mfa:read |
List a user's MFA devices |
plugipay:payments:read |
(Plugipay) read payments |
plugipay:* |
Anything in Plugipay |
* |
Everything (root) |
The full action catalog per Forjio product lives in that product's docs. Huudis policies typically reference huudis:* actions; cross-product permissions are uncommon.
Resource ARNs
Huudis resources have ARNs of the form forjio:huudis::<accountId>:<type>/<id>. Examples:
forjio:huudis::acc_01KPG…:user/usr_01KPG…forjio:huudis::acc_01KPG…:oidc-client/oc_01KPG…forjio:huudis::acc_01KPG…:role/BillingReaderforjio:huudis::acc_01KPG…:*(everything in this workspace)
ARN wildcards work at any segment past the last :. Cross-workspace ARNs in your policies are honored but never evaluate to allow against another workspace's resources — Huudis enforces workspace-isolation as a meta-rule.
Condition keys
Condition keys reflect attributes of the request itself. Useful ones:
| Key | Type | Value |
|---|---|---|
forjio:MfaPresent |
bool | Whether the calling session passed MFA. |
forjio:CurrentTime |
datetime | Server time at evaluation. |
forjio:SourceIp |
string | Caller's IP. Pair with IpAddress operator. |
forjio:PrincipalType |
string | user, service_account, role. |
huudis:WorkspaceSlug |
string | Slug of the active workspace. |
Pass custom keys (your own) in the authz-check call's context block — useful when delegating authz decisions to Huudis from another service.
System policies
Huudis ships a handful of canned policies. Stable IDs (pol_system_*) survive across deployments. The current set:
| Policy | Allows |
|---|---|
HuudisAdmin |
Everything within Huudis. |
HuudisReadOnly |
All *:read actions in Huudis. |
HuudisBillingReader |
Read billing, plan info, invoices. |
HuudisAuditExporter |
Read + export the audit log; nothing else. |
PlugipayAdmin |
Everything within Plugipay (only visible if Plugipay is enabled). |
System policies can be attached like any other — they just can't be edited or deleted.
Events
No events for policy CRUD. Audit-log entries (iam.policy.created, iam.policy.updated, iam.policy.deleted) capture the same data, with the document JSON in metadata.
Next
- Attachments — the join between policy and principal.
- Authz — the live authorization check.
- Groups and Roles — common attachment targets.