Skip to content

Authorization

PlotPress’s authorization model is per-dashboard. Each dashboard folder declares its own users and its own connections. There is no workspace-wide “everyone can read X.”

NounDefined inStored in
UserOIDC provider (or Email OTP for self-hosted demos)SQLite (id, email, last seen)
Roledashboards/<name>/users.yamlparsed at boot
Connectiondashboards/<name>/connections.yamlparsed at boot, never persisted

users.yaml defines named roles (e.g. analysts, exec) and how a user qualifies for each — by static email list or OIDC claim.

A query runs if and only if the requesting user holds at least one role listed in the target connection’s allowed_users, and that connection lives in the same dashboard folder as the page making the request.

flowchart LR
  U[User<br/>email] -->|OIDC| S[Session]
  S --> R{users.yaml<br/>role resolution}
  R -->|claim match| R1[role: analysts]
  R -->|email list| R2[role: exec]
  Q[Query] --> C[(connection: warehouse)]
  C -->|allowed_users| R1
  R1 -.->|allowed| Q
  • Not row-level security. PlotPress controls which connections a viewer can hit. Push row filtering down into the database (RLS or per-role views).
  • Not a query builder. The backend executes against database views (the primary path) or pre-registered SQL files (the fallback — see Authoring → Queries as fallback).
  • Not a secret manager. Connection DSNs read from environment variables; PlotPress never writes them to disk.

Every query execution writes one row to audit_log in SQLite: timestamp, user, dashboard, view (or query name), parameters, connection, duration, row count, error. Backups of the SQLite file are the audit backup.