Canic 0.9: Two Big Wins for Auth & Access Control
We’ve been heads-down on Canic’s foundations, and with 0.9 we’re excited to share two changes that materially improve how auth and access control work — both in power and clarity.
These aren’t incremental tweaks. They unlock new capabilities while making the system easier to reason about.
1. A Brand-New Access Model (Finally!)
Auth in Canic is now built around a single, expressive access expression model.
Instead of splitting access checks across guard, auth, env, and rule stages, endpoints now declare exactly what they require using one requires(...) clause.
Access rules are written as composable expressions using explicit predicates like:
-
caller::… -
app::… -
self_env::…
All checks are evaluated by one async evaluator, with deterministic short-circuiting and precise metrics.
What that looks like in practice
#[canic_update(requires(any(
caller::is_root(),
all(
caller::is_controller(),
not(app::is_readonly()),
custom(HasPaidAccount),
),
)))]
async fn update_critical_settings(
input: SettingsInput,
) -> Result<(), canic::Error> {
// …
}
At a glance, you can see:
-
how rules are combined (any,all,not) -
who is allowed to call it -
what app state must be true -
where custom async logic fits in
No hidden ordering. No implicit stages. No guessing.
Grouping & Composition (The Part That Makes This Powerful)
Access predicates are grouped explicitly using boolean combinators:
-
all(...)→ every predicate must pass -
any(...)→ at least one predicate must pass -
not(...)→ invert a predicate or whole group
Groups can be nested arbitrarily, read top-down, and evaluated exactly as written. Evaluation stops on the first failure, and only that denying predicate is recorded in logs and metrics.
The result: access logic that is local, readable, and auditable.
2. Delegation You Can Actually Scale
Earlier in 0.9, we also landed a major upgrade to Canic’s delegation and trust model:
-
Root is the sole delegation authority
-
Shards store proofs locally and mint tokens without calling root
-
Tokens are verified locally by any canister
-
Issuance is explicit about certified-data requirements
-
No runtime dependency on root for verification
This unlocks high-throughput, low-latency auth without sacrificing correctness.
