Skip to content
AXOWLDevelopers
Quickstart

Permits (SignedPermit)

A SignedPermit is a cryptographically signed authorization for a specific action. The Brain & Permit principle: Axowl issues the permit; your plugin/app performs the action and verifies the permit. Base path: /api/org/{slug}/permits (authenticated).

Method · RoutePurpose
POST /issueIssue a SignedPermit for the caller’s ConnectedId + requested scope

The permit is always issued for the caller’s own ConnectedId in the organization named by {slug} — there is no way to request a permit on behalf of another badge. A person who belongs to several organizations holds a separate badge in each; the one in the route’s organization is the one that counts.

FieldTypeNotes
requestedScopestring, requiredScope key from the permission scopes catalog.
ttlSecondsint, optional (default 30)1–300. A value outside that range is refused with 400 and error: "invalid_ttl_seconds".
idempotencyKeystring, optionalReplays the same permit within its TTL. Scoped to your badge and scope — your key cannot collide with another caller’s.
contextobject, optionalFree-form, embedded in the permit as a context claim.

POST /issue runs these before signing:

  1. Organization — resolve {slug}; the caller must be a member (enforced upstream by tenant resolution).
  2. Badge — resolve the caller’s ConnectedId in that organization.
  3. Active — is the ConnectedId active?
  4. Revocation — is the ConnectedId on the revocation list?
  5. Scope — does the member hold the requested scope (an active, unexpired grant)? A wildcard grant counts when it covers the request under the same rules as a permission check — a read-only wildcard does not cover a write action — and an Owner-only scope needs the Owner or a grant that names it explicitly.
  6. Seal tier — derived from the org’s SecurityMode.
  7. Sign — issue the permit, RS256-signed with the org’s signing key.

Failure shapes: 400 no organization context, or ttlSeconds out of range · 404 no badge for the caller in that organization · 403 badge inactive, revoked, or missing the scope · 500 the org has no signing key (Settings → Keys).

{ "decision": "…", "reason": null,
"permit": { "scope": "…", "actorConnectedId": "…", "sealTier": 0, "idempotencyKey": "…",
"issuedAt": "…", "expiresAt": "…", "signature": "<RS256 JWT>" } }

When the scope is missing the answer is 403 with decision: "Deny", the reason, and permit: null.

The permit is verifiable by your side against the org’s published JWKS — no shared secret. Permits draw their authority from the same sealed RBAC snapshot as everything else — see Roles & permissions and Permission scopes.