Published May 23, 2026
| Version v1.0.0
Software
Open
chain simple forms / surveys into longer runs using the power of R to generate pretty feedback and complex designs https://formr.org
Authors/Creators
- 1. Wilhelm Wundt Institute of Psychology, University of Leipzig
- 2. Georg Elias Müller Institute of Psychology, University of Goettingen
Description
Heads up: every existing API integration breaks on upgrade. All current access tokens are invalidated and every API client secret is wiped. Plan a maintenance window, then have each credential owner mint a new secret, select their scopes, and (optionally) restrict the credential to specific runs. See UPGRADING-v1.0.0.md for the audit + rotation checklist before you bump FORMR_TAG.
Added
- Versioned v1 API at
/api/v1/<resource>. OAuth2 with one-hour access tokens. Resources includeuser,surveys,runs/{name}, and per-run sub-resourcessessions,results,files,structure. Twelve scopes —user:read/write,survey:read/write,run:read/write,session:read/write,data:read,file:read/write— checked before the resource is looked up, so a token without the right scope can't probe which runs or surveys exist. - New admin level "API access" (admin = 2). Only users at this level (or above) can mint or use API credentials. Existing
admin = 1accounts keep their web-admin rights but lose API access until a SuperAdmin promotes them from the user-management page. - Multiple labelled API credentials per user. The API tab at
/admin/accountis now a credential table — each row has its own label, scopes, run allowlist, rotate button, and delete button. A common pattern: one narrow read-only credential for a dashboard, plus a broader credential for a cron job. Labels are unique per user; the labelinternalis reserved. - One-time secret display. Client secrets are shown only at issuance and rotation; the server stores a hash. A forgotten secret must be rotated, not recovered.
- Per-credential run allowlist. Restrict a credential to one or more specific runs at creation / rotation; an empty list means unrestricted (the legacy behaviour). Internal R-callback tokens (used by OpenCPU rendering) are automatically pinned to the run that minted them.
- Unit-session history endpoint
GET /v1/runs/{name}/unit_sessions. One row per (participant × unit × iteration) — the complement to/v1/runs/{name}/sessions, which only exposes each participant's current unit. Rows arrive ordered so consecutive rows per participant are trajectory edges. Filters:?session=,?testing=,?since=; pagination vialimit(default 1000, max 10000) andoffset. Scope:session:read. The R package wraps this asformr_api_unit_sessions(). - Trajectory-Sankey by default in the Overview script. New runs get an Overview script that renders a Sankey of participants' actual paths through the study, with terminal arrows to Completed, Expired, and Active @ <position>. Re-iterations (diary, longitudinal) collapse to one node per position, with an
(avg N visits)label suffix when the average exceeds one. Customise freely — drop in any R, knitr chunks, plotly / ggplot, raw markdown. Existing Overview scripts are not touched.
Changed (BREAKING)
- OAuth tokens and client secrets are now stored as hashes at rest. On upgrade, all access tokens, refresh tokens, and authorization codes are truncated, and every client secret is zeroed. Every API client must mint a new secret from
/admin/account#apiafter upgrade. Plan a maintenance window for any unattended cron jobs that hold long-lived tokens. - Credentials must now explicitly request scopes. The old "all scopes by default" no longer holds — after upgrade, users open the API tab, pick the read/write scopes their credential should carry, optionally restrict it to specific runs, then click Create credential / Rotate. Tokens minted under the old default no longer work.
OAuthHelperreshaped for multi-client per user. If you maintain a downstream integration that callsOAuthHelperdirectly, the single-client lookups (getClient(User),refreshToken(User, ...),deleteClient(User)) are replaced bylistClientsForUser,getClientForUser,rotateClient,deleteClient(User, $clientId), plus an emergency-revokedeleteAllClientsForUser. In-repo callers were migrated in the same commit.
Fixes
- Overview script errors are now visible to the admin. Errors in the Overview script no longer disappear into a blank box — they appear as a red banner with a collapsible debugger output, in the same spot the rendered iframe would have shown.
- R / OpenCPU errors surface in admin and cron contexts. Real participants still see only the public message; admins (and the queue daemons) now see the actual error body, matching the behaviour the test runner already had.
- The Overview script's settings chunk no longer leaks the embedded API token. Previously the chunk source was echoed in admin / test contexts, briefly showing the
.formr$access_token = '…'line that authenticates the embedded R session. Side effects (token + helper assignment) still apply to subsequent chunks. - Survey import via Google Sheet no longer leaks a tmp file when the upload-items step throws.
- Credential creation now commits or rolls back as a single transaction. Previously a partial failure could leave a stub credential row with an empty scope / secret.
Security
- Strict identifier validation in
ORDER BYclauses. The previous pass-through let any string flow intoORDER BYverbatim — a future caller forwarding a?sort=request param would have been a SQL-injection sink. Onlycolumnortable.column(with optional backticks) are accepted now; SQL function calls require an explicitDB::raw()escape hatch. - Parameterised the last interpolating SQL helpers. Two
LIKEfilters in user management (superadmin email search) and admin results (session filter) were concatenating user input into the SQL literal; both are now bound through placeholders with wildcard escaping. Same pattern fixed inDB::like(). - Operators are encouraged to upgrade and to rotate any OAuth client secrets after upgrading. A detailed advisory will follow once adoption is broader.
Schema
- Patch
050_hash_oauth_tokens.sql— switch OAuth tokens to hashed storage; truncates token tables. - Patch
051_hash_client_secrets.sql— zero existing client secrets so the new hashed-storage path is used on first rotation. - Patch
052_oauth_client_runs.sql— add the per-credential run allowlist, widen the scope column, clear "default scope" rows. - Patch
053_oauth_access_token_run_ids.sql— per-token run allowlist for internal R-callback tokens. - Patch
054_oauth_client_labels.sql—oauth_clients.labelwithUNIQUE(user_id, label), enabling multiple labelled credentials per user.
Files
rubenarslan/formr.org-v1.0.0.zip
Files
(4.3 MB)
| Name | Size | Download all |
|---|---|---|
|
md5:823fd9d78c41e114f50189a3a2032abe
|
4.3 MB | Preview Download |
Additional details
Related works
- Is supplement to
- Software: https://github.com/rubenarslan/formr.org/tree/v1.0.0 (URL)
Software
- Repository URL
- https://github.com/rubenarslan/formr.org