惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Y
Y Combinator Blog
The GitHub Blog
The GitHub Blog
云风的 BLOG
云风的 BLOG
Engineering at Meta
Engineering at Meta
Google DeepMind News
Google DeepMind News
aimingoo的专栏
aimingoo的专栏
Recent Announcements
Recent Announcements
A
About on SuperTechFans
U
Unit 42
MyScale Blog
MyScale Blog
J
Java Code Geeks
博客园_首页
Blog — PlanetScale
Blog — PlanetScale
D
Docker
Microsoft Azure Blog
Microsoft Azure Blog
博客园 - 司徒正美
量子位
月光博客
月光博客
G
Google Developers Blog
V
V2EX
博客园 - 聂微东
宝玉的分享
宝玉的分享
IT之家
IT之家
Vercel News
Vercel News

Cerbos - All Posts

Authentik vs Keycloak: Self-hosted IdP comparison Mapping business requirements to authorization policy for automotive Fine-grained authorization for AI gateways EIC 2026: Stop counting agents, protect what they can touch Agent skill for writing authorization policies in Claude Desktop Identity security in 2026 EIC 2026 takeaways: the identity stack built for humans will not hold up for AI agents Already have authentication? Here's the authorization layer you still need. Tokens are authorization decisions: a guide to policy-driven token issuance What is a Runtime Authorization Platform It's a dimmer switch, not a kill switch. How CISOs are rethinking AI agent governance From maps to bitmaps (and from bitmaps to bitmaps) AuthZEN, Shared Signals, SCIM Events, IPSIE: Notes from the OpenID Enterprise Panel How do you update authorization policies without redeploying your application? IIW42 recap: Where agent authorization got real Cerbos PDP v0.52.0/v0.53.0: Engine performance, security hardening, and CEL path functions Authorization Management Platforms: what they do, how they work, and where they fit PocketOS AI coding agent deleted a production database in 9 seconds Non-Human Identity management still has a blind spot Supabase alternative in 2026: Best open source auth options Benefits of on-premise authorization: Why enterprises are moving toward self-hosted Authorization policies: How to write, test, and validate them (faster with AI) Agent skill for writing authorization policies How much does it cost to build authorization in-house? Why centralized authorization governance reduces incident response time OPA alternative Why AI agents make authorization a right now problem Modernizing legacy application authorization: why it’s your biggest security blind spot How to add authorization to legacy applications without code changes 5 authorization blind spots auditors find, and how to fix them
Query plan adapter for Convex
Alex Olivier · 2026-02-09 · via Cerbos - All Posts

Externalized authorization moves access control out of your application code and into a dedicated policy engine. With Cerbos, you define who can do what in policy files that live alongside your code in version control. At runtime, your application asks Cerbos for a decision rather than implementing the logic itself. Policies can express roles, attributes, conditions, and relationships - and they can change without redeploying your application.

Individual access checks are straightforward: pass a principal, resource, and action to checkResources and get a permit or deny. But listing resources - "show me everything this user can see" - is a harder problem. Checking every row one by one means fetching data the user may never be allowed to access. That is wasteful at best and a scaling bottleneck at worst.

The PlanResources API takes a different approach. Instead of evaluating specific resource instances, Cerbos partially evaluates your policies and returns a query plan: an abstract syntax tree that describes the conditions under which access is granted. This AST can be translated into any query language, pushing authorization filtering down to the data layer where it belongs. The database applies the filter using its own indexes and query engine, rather than your application processing rows it will discard.

Convex is a reactive backend platform where your database, server functions, and real-time sync all live in one place. Today we are releasing @cerbos/orm-convex, a query plan adapter that translates Cerbos query plans into Convex filter functions.

The challenge with Convex

Convex queries use a functional filter API - q.eq, q.lt, q.and, and so on - rather than SQL. This means a straightforward SQL translation will not work. The adapter needs to produce composable filter functions that Convex's query engine understands natively.

There is also a gap in what Convex can express at the database level. String operations like contains and collection operators like exists have no Convex equivalent. The adapter addresses this with a two-tier approach: operations that Convex supports natively become database-level filters, and everything else is evaluated as a post-filter in JavaScript.

How it works

queryPlanToConvex takes a Cerbos plan and returns up to two functions: a filter for the database and an optional postFilter for client-side evaluation.

import { queryPlanToConvex, PlanKind } from "@cerbos/orm-convex";

const plan = await cerbos.planResources({
  principal: { id: "user1", roles: ["USER"] },
  resource: { kind: "task" },
  action: "view",
});

const { kind, filter, postFilter } = queryPlanToConvex({
  queryPlan: plan,
  mapper: {
    "request.resource.attr.status": { field: "status" },
    "request.resource.attr.priority": { field: "priority" },
  },
  allowPostFilter: true,
});

if (kind === PlanKind.ALWAYS_DENIED) return [];

let query = ctx.db.query("tasks");
if (filter) query = query.filter(filter);
let results = await query.collect();
if (postFilter) results = results.filter(postFilter);
return results;

DB-level vs. post-filter operators

Pushed to Convex DB Evaluated in JavaScript (post-filter)
eq, ne, lt, le, gt, ge contains, startsWith, endsWith
and, or, not hasIntersection
in, isSet exists, exists_one, all

For and expressions that mix both tiers, the adapter splits the tree: DB-pushable children go to filter, the rest go to postFilter. For or expressions with any unsupported child, the entire expression is evaluated client-side to avoid returning false positives.

Full example

Consider a policy that allows users to view tasks assigned to them, or tasks with a priority above a threshold:

# policies/task.yaml
apiVersion: api.cerbos.dev/v1
resourcePolicy:
  resource: task
  version: default
  rules:
    - actions: ["view"]
      effect: EFFECT_ALLOW
      roles: ["USER"]
      condition:
        match:
          any:
            of:
              - expr: request.resource.attr.assignee == request.principal.id
              - expr: request.resource.attr.priority >= 3

Inside a Convex query function:

import { GRPC as Cerbos } from "@cerbos/grpc";
import { queryPlanToConvex, PlanKind } from "@cerbos/orm-convex";
import { query } from "./_generated/server";

const cerbos = new Cerbos("localhost:3592", { tls: false });

export const listTasks = query({
  handler: async (ctx) => {
    const plan = await cerbos.planResources({
      principal: { id: "user1", roles: ["USER"] },
      resource: { kind: "task" },
      action: "view",
    });

    const { kind, filter, postFilter } = queryPlanToConvex({
      queryPlan: plan,
      mapper: {
        "request.resource.attr.assignee": { field: "assignee" },
        "request.resource.attr.priority": { field: "priority" },
      },
    });

    if (kind === PlanKind.ALWAYS_DENIED) return [];

    let q = ctx.db.query("tasks");
    if (filter) q = q.filter(filter);
    let results = await q.collect();
    if (postFilter) results = results.filter(postFilter);
    return results;
  },
});

Because this policy only uses comparison operators, the adapter pushes the entire condition to the Convex database layer - no post-filter is needed and allowPostFilter is not required.

Opting into post-filtering

By default, queryPlanToConvex throws if the plan requires a post-filter. This is a deliberate safety choice - post-filtering means documents are read from the database before the full authorization condition is applied. Pass allowPostFilter: true to enable it when your policies need string or collection operators.

If your policies only use comparisons, in, isSet, and logical combinators, you do not need the flag. The database filter alone will enforce the complete policy.

Get started

npm install @cerbos/orm-convex

The full documentation and source are available on GitHub. If you have questions, join the Cerbos community Slack.