Phase 5a of DESIGN.md section 12 (spec #13): IAM-style policy documents stored on Authentik groups.
What is in it
Format (docs/POLICY-FORMAT.md): PolicyParser fails closed. An unknown spec or version, a non-Allow effect (including Deny), an unknown action, a resource outside [A-Za-z0-9_]+, or malformed JSON grants nothing and logs a warning. parseStrict names the problem for the editor.
Generator: PolicyGenerator writes the canonical form: one statement per action, in the order hasAccess, read, insert, edit, delete; resources sorted; no *. Compact and pretty writers use a fixed key order. Every generated document is checked to round-trip to exactly the permissions it came from.
Config: policySpec (qqq-iam), policyVersion (1.0.0), policyAttribute (qqq.io/policy), policyClaim (qqq_policy) and policyTwoPersonApproval (off), all validated. A host can keep its own spec name, attribute and claim.
Runtime:
AuthentikPolicyClaimMapper reads the claim from the ID token, else the access token, and adds the permissions. It has an applySecurityKeys hook as the record-lock extension point.
PolicyPermissions.fromClaims serves a host's own customizer.
AuthentikGroupPermissionMapper also adds the claim.
Graph and resolver: GroupGraph parses each group's qqq.io/policy and fails closed per group; a bad document is listed as malformed. EffectivePermissionResolver includes policy grants, so effective permissions, the subset rule and the last-admin check see them.
Blueprint example: the scope mapping merges the policies of all_groups() into the claim. PolicyClaimMappingIT pins it on Authentik 2026.8.3 through the property-mapping test endpoint: inherited parents, object-valued attributes, other specs skipped, and an empty document for users without policies.
Tests
CI=true ./mvnw verify: 180 unit tests and 42 contract tests on Authentik 2026.8.3, all green; checkstyle and JaCoCo pass. New tests:
PolicyParserTest: 24 fail-closed cases plus semantics.
PolicyGeneratorTest: canonical bytes, 500 random round trips, refusals.
AuthentikPolicyClaimMapperTest: ID token, access token, fail closed, custom names, the hook.
Phase 5a of DESIGN.md section 12 (spec #13): IAM-style policy documents stored on Authentik groups.
## What is in it
- **Format** (`docs/POLICY-FORMAT.md`): `PolicyParser` fails closed. An unknown spec or version, a non-`Allow` effect (including `Deny`), an unknown action, a resource outside `[A-Za-z0-9_]+`, or malformed JSON grants nothing and logs a warning. `parseStrict` names the problem for the editor.
- **Generator**: `PolicyGenerator` writes the canonical form: one statement per action, in the order hasAccess, read, insert, edit, delete; resources sorted; no `*`. Compact and pretty writers use a fixed key order. Every generated document is checked to round-trip to exactly the permissions it came from.
- **Config**: `policySpec` (`qqq-iam`), `policyVersion` (`1.0.0`), `policyAttribute` (`qqq.io/policy`), `policyClaim` (`qqq_policy`) and `policyTwoPersonApproval` (off), all validated. A host can keep its own spec name, attribute and claim.
- **Runtime**:
- `AuthentikPolicyClaimMapper` reads the claim from the ID token, else the access token, and adds the permissions. It has an `applySecurityKeys` hook as the record-lock extension point.
- `PolicyPermissions.fromClaims` serves a host's own customizer.
- `AuthentikGroupPermissionMapper` also adds the claim.
- **Graph and resolver**: `GroupGraph` parses each group's `qqq.io/policy` and fails closed per group; a bad document is listed as malformed. `EffectivePermissionResolver` includes policy grants, so effective permissions, the subset rule and the last-admin check see them.
- **Blueprint example**: the scope mapping merges the policies of `all_groups()` into the claim. `PolicyClaimMappingIT` pins it on Authentik 2026.8.3 through the property-mapping test endpoint: inherited parents, object-valued attributes, other specs skipped, and an empty document for users without policies.
## Tests
`CI=true ./mvnw verify`: 180 unit tests and 42 contract tests on Authentik 2026.8.3, all green; checkstyle and JaCoCo pass. New tests:
- `PolicyParserTest`: 24 fail-closed cases plus semantics.
- `PolicyGeneratorTest`: canonical bytes, 500 random round trips, refusals.
- `AuthentikPolicyClaimMapperTest`: ID token, access token, fail closed, custom names, the hook.
- `PolicyGraphTest`: inheritance, per-group fail-closed, catalog filtering.
- Mapper and config additions.
- `PolicyClaimMappingIT`.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Phase 5a of DESIGN.md section 12 (spec #13): IAM-style policy documents stored on Authentik groups.
What is in it
docs/POLICY-FORMAT.md):PolicyParserfails closed. An unknown spec or version, a non-Alloweffect (includingDeny), an unknown action, a resource outside[A-Za-z0-9_]+, or malformed JSON grants nothing and logs a warning.parseStrictnames the problem for the editor.PolicyGeneratorwrites the canonical form: one statement per action, in the order hasAccess, read, insert, edit, delete; resources sorted; no*. Compact and pretty writers use a fixed key order. Every generated document is checked to round-trip to exactly the permissions it came from.policySpec(qqq-iam),policyVersion(1.0.0),policyAttribute(qqq.io/policy),policyClaim(qqq_policy) andpolicyTwoPersonApproval(off), all validated. A host can keep its own spec name, attribute and claim.AuthentikPolicyClaimMapperreads the claim from the ID token, else the access token, and adds the permissions. It has anapplySecurityKeyshook as the record-lock extension point.PolicyPermissions.fromClaimsserves a host's own customizer.AuthentikGroupPermissionMapperalso adds the claim.GroupGraphparses each group'sqqq.io/policyand fails closed per group; a bad document is listed as malformed.EffectivePermissionResolverincludes policy grants, so effective permissions, the subset rule and the last-admin check see them.all_groups()into the claim.PolicyClaimMappingITpins it on Authentik 2026.8.3 through the property-mapping test endpoint: inherited parents, object-valued attributes, other specs skipped, and an empty document for users without policies.Tests
CI=true ./mvnw verify: 180 unit tests and 42 contract tests on Authentik 2026.8.3, all green; checkstyle and JaCoCo pass. New tests:PolicyParserTest: 24 fail-closed cases plus semantics.PolicyGeneratorTest: canonical bytes, 500 random round trips, refusals.AuthentikPolicyClaimMapperTest: ID token, access token, fail closed, custom names, the hook.PolicyGraphTest: inheritance, per-group fail-closed, catalog filtering.PolicyClaimMappingIT.🤖 Generated with Claude Code