anfra-user
A demo add-on for Anfra · v0.1

Serving
the right data.

Row-based access for Anfra.

anfra-user puts your Anfra repo behind sign-in. Each person sees only their own rows: their country, their vendor, their accounts.

A server rack with eyelashes, glossy lips and long nails, captioned: this server is serving.
youSales reps should log in and see only their own countries' orders.

agentScope sales by customers.country, from each user's country. No country: they see nothing.
wrote anfra-user.yml · 4 test users
$anfra-user verify
OK: 48 checks, 4 users, 12 queries.
Live at 127.0.0.1:8080. ana@ sees Brazil, ben@ sees USA + Canada.

How it works

anfra-user sits between the browser and anfra serve. It signs people in, works out what each one may see, and adds that filter to every query on the server, where nobody can take it off.

You set up two things

1

Access rules

A scope says which field limits a user's rows, and which user attribute holds their values.

scopes:
  - dataset: sales
    field: customers.country
    attribute: country
    default_values: []  # none: nothing
2

Users

An email and password, plus the values each person may see.

anfra-user users add \
  ana@acme.com \
  --attr country=Brazil

anfra-user users add \
  maria@acme.com \
  --attr country=__ALL__

Your pages and Anfra Data Apps keep working as they are: anfra-user serves them behind sign-in and adds each user's scope to their queries.

Same page. Different numbers.

One sales dashboard, one scope on customers.country. Everyone opens the same URL.

Signed in ascountrySees
ana@acme.comBrazilBrazil's orders only
ben@acme.comUSA, CanadaThe USA and Canada
maria@acme.com__ALL__Every country
new@acme.comnot set"No country assigned to your account yet"

Built so the filter can't come off.

The browser never chooses AQL. The gateway refuses to start on anything it can't show is safe, and tests every query as every user.

✓

Queries come from your files

Pages are parsed on the server. The browser sends a query's name, never its text, so a tampered page runs nothing new.

✓

Escapes are refused

of_all, exclude, keep, with_relationships and friends can drop a filter. check stops the server if any query or metric uses them.

✓

Empty means nothing

No attribute, no rows. A dataset without a scope is refused unless you mark it public.

✓

Edits are re-checked live

Change a page while serving: it's re-read and re-checked, and a failing query is blocked until it's fixed.

$ anfra-user verify PASS ana kpis narrowed PASS ana byCountry own data only PASS new kpis 0 rows PASS maria kpis __ALL__ = unscoped FAIL ana share total: unchanged by the scope 1 failure.

The leak test compares each user's results with the unscoped data and with everything outside their scope. A metric that ignores the filter shows up, whatever AQL produced it.

Get started

Made for people who build with AI agents. Install the skill and describe the access you want; the agent does the rest, and checks its work.

With Claude Code (recommended)

Add the plugin, then ask in plain words.

# in Claude Code
/plugin marketplace add khanh-tran-quoc/anfra-user
/plugin install anfra-user@anfra-user

# then just ask
"Put this repo behind sign-in. Each sales
rep sees only their countries' orders."

Pairs with the Anfra skills for modeling, queries and Data Apps.

By hand

Node 23.6+, Docker, and an Anfra repo that anfra serve runs.

git clone https://github.com/khanh-tran-quoc/anfra-user
cd anfra-user && npm install
docker compose up -d        # users database

# in your anfra repo, with anfra serve running
node ../anfra-user/src/cli.ts check
node ../anfra-user/src/cli.ts users add …
node ../anfra-user/src/cli.ts verify
node ../anfra-user/src/cli.ts serve

Full reference in the README.

Good to know

Demo-grade sign-in. Email and password, sessions in an HttpOnly cookie, bcrypt hashes. No rate limiting, lockout, password reset or MFA yet. It serves on 127.0.0.1. Great for demos and internal tools on your machine; don't put it on the internet as is.
Why not Anfra's own permission rules?

They aren't enforced in local Anfra yet. anfra-user enforces scopes itself, in a gateway you control. If native enforcement ships, the same idea maps onto it.

Can my existing Data Apps use it?

Yes, if their queries are fixed text in the file. Point apps: at your apps folder and they run behind sign-in, scoped, unchanged. Plugins (export, render, lineage) aren't available behind the gateway yet.

Does anfra need to be reachable?

Only by the gateway. anfra serve has no sign-in, so anyone who can reach it bypasses anfra-user. Keep it on loopback.

Is this an official Anfra project?

No. It's a demo built for fun, MIT licensed.