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 Allow to perform an action.
  • Explicit Deny wins over any Allow. Use Deny to enforce hard guardrails (e.g. "never touch production-billing").
  • No "policy version" branching — updates increment a version counter 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-onlyPATCH 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.

Response201 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 see Plugipay* 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/BillingReader
  • forjio: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.