Security model

How Anythink isolates projects, encrypts secrets, enforces row-level security, and authorises every API and service request.

Last updated

This page explains how Anythink protects your project: how projects are kept apart, how callers prove who they are, how each request is checked against roles and row-level security, and how secrets, files and payments are handled. It ends with what Anythink expects you to do on your side, and how to review your own project's settings.

It's an explainer. For step-by-step tasks, follow the links in each section.

Layer What it protects Read more
Project isolation One project's data, users, keys and settings from another Environments and migrating data
Authentication Who is calling: a user, an API key or an Anythink service Sign in users: email, tokens and API keys, API keys
Authorisation What that caller may do, through roles and permissions Roles and permissions
Row-level security Which records a user can reach Groups and row-level security
Secrets and credentials API keys and tokens your project uses Store API keys and tokens as secrets
Files Uploads and downloads Upload and manage files
Payments Card details and payouts How payments and subscriptions work
Transport Data between your app and Anythink This page

Project isolation#

A project is the unit of isolation. Each project has its own data model, records, users, roles, API keys, secrets, files, workflows and settings.

  • Requests name the project. Project API paths start with /org/{project_id}. On endpoints that need a signed-in user or a key, Anythink checks that the caller belongs to that project before the request reaches your data.
  • Credentials belong to one project. A user's access token, refresh token and API keys are issued for one project and are refused on another.
  • Data is stored with its project. Records, files, secrets and keys carry the project they belong to, and Anythink's queries filter by it.
  • Settings aren't shared. Allowed Application URLs, sign-up settings, integrations and payment settings are configured per project.

Use separate projects for development, staging and production. A test user, a leaked development key or a broken workflow in development then has no route to production data. See Environments and migrating data for setting up and promoting between them.

Authentication#

Apart from public endpoints, such as sign-in and public files, a request to your project is made as one of three kinds of caller.

Caller How it proves who it is Typical use
A signed-in user Authorization: Bearer <access token> Your web and mobile apps, and the Anythink dashboard
An API key x-api-key: <key> Your own servers, scripts and CI jobs
An Anythink service A service identity issued inside the platform Workflows, search indexing, email and other background work

Users: access and refresh tokens#

A user signs in with email and password, or with a social provider, and receives a pair of tokens:

Token Lifetime Notes
Access token 30 minutes A signed JWT that names the user and the project. Sent on every request.
Refresh token 30 days Single use. Each refresh revokes it and issues a new pair. Signing out revokes it.

Anythink stores passwords and refresh tokens only as one-way hashes, never as plain text. A refresh token is tied to the project that issued it. See Sign in users: email, tokens and API keys and Anythink SDK: sign-in and sessions.

Social sign-in#

With Apple, Google, GitHub or LinkedIn sign-in, Anythink verifies the provider's identity server-side, then finds or creates the user in your project and returns the same Anythink tokens as email sign-in. The provider's client secret stays in Anythink and your app never handles it. New users get the role you set as Default role for new users. See Social sign-in with Apple, Google, GitHub and LinkedIn.

API keys#

An API key lets code you run yourself call your project without a signed-in user.

  • Scoped. A key carries the permissions you choose when you create it, and is checked against them on each request.
  • Bounded by its creator. When a key is created, it can only be given permissions its creator holds. Any you ask for beyond that are left off.
  • Expiring. Every key has an expiry date, and you can revoke a key at any time.
  • Shown once. Anythink stores a hash of the key, so the full key is shown only when you create it.
  • Acts as its creator for row-level security. A key sees the records its creator can see.

See API keys.

Anythink services#

Anythink's own background services, such as the workflow engine and the search indexer, call the API with their own service identities. Endpoints that accept them are marked for service access individually. Workflow steps act as a trusted service, so they read every record in the project. Filter explicitly in the step when it acts for one user. See Groups and row-level security.

Authorisation: roles and permissions#

Once Anythink knows who's calling, it checks what they may do. Each endpoint declares the permission it needs, and Anythink checks it on each request.

  • Permissions are named {entity}:{action}. For example orders:read, orders:create, orders:update and orders:delete. Platform features use anythink_ resources, such as anythink_files:read or anythink_secrets:create. See Permissions reference.
  • A user holds the permissions of their role. Each user in a project has one role. A request that needs a permission the role lacks returns 403 Forbidden.
  • API Access gates your own entities. A role needs API Access turned on before its users can call the data endpoints for your entities.
  • Field access hides columns. A role can be limited to some fields of an entity, such as hiding cost price or internal notes.
  • Changes apply straight away. Permissions are read on each request, so a user doesn't need to sign in again after you change their role.

Administrators are users on the project's Admin User role. They pass permission checks, see every field, bypass row-level security, and can call administrator-only endpoints such as managing roles. Keep this role for the people who run the project, not the people who use your app.

See Roles and permissions.

Row-level security#

Roles decide whether a user can read orders at all. Row-level security (RLS) decides which orders records they can reach.

  • A switch per entity. Turn on Enable Row-Level Security for an entity, and reads, updates and deletes through the REST API are limited to records the user holds a grant for.
  • User grants and group grants. A grant gives one user, or every member of a group, access to one record, either read-only or read-write. Group grants apply once a project administrator turns on Enable group-level row access.
  • Reads are filtered on the server. Lists, counts and paging include only the records the user can reach, and a record they can't reach returns 404. Your app calls the normal endpoints with the user's token. There are no per-user queries to write and nothing to filter on the client.
  • Creators keep access. When a user or API key creates a record on an RLS entity, Anythink grants the creator read-write access to it.
  • Administrators configure access. Project administrators manage grants on records in the dashboard, and choose which workflows share records and with whom.

RLS narrows what roles allow. It never widens it: a user still needs the entity's permission on their role. See Groups and row-level security.

Secrets and credentials#

Credentials you give Anythink are encrypted before they're stored. That covers:

  • secrets you store for workflows
  • integration connections, such as Google and Slack
  • social sign-in client secrets and Apple keys
  • push notification credentials

After you save them, the dashboard and the CLI don't show these values again. Secret lists show names and dates, not values. Keep your own copy in a password manager.

Workflows use a secret by name, and Anythink substitutes the value when the step runs:

text
{{ $anythink.secrets.PARTNER_API_KEY }}

Step parameters in the job history show the expression, not the value. See Store API keys and tokens as secrets.

Files#

Files are stored in object storage, outside your database, under your project.

  • Private files are downloaded through short-lived signed links. GET /files/{id}/get checks the caller's anythink_files:read permission, then redirects to a signed address that works for one minute. GET /files/{id}/url returns one that works for five minutes. File bytes don't pass through the API.
  • Public files are served from the CDN to anyone with the address. Mark a file public only when it's meant for everyone, such as a logo or a published image.

See Upload and manage files.

Payments#

AnythinkPay takes card payments through Stripe Checkout, and in-app purchases through Apple.

  • Card details go to Stripe. Your customers enter card details on Stripe's pages. Card numbers never reach Anythink and aren't stored by Anythink.
  • Payouts go to your Stripe account. You connect your own Stripe account, and payments for what you sell are paid out to it.
  • Provider events are verified. Anythink checks the signature on Stripe's webhook events, and verifies Apple's signed transactions, before it updates a subscription.

See How payments and subscriptions work.

Transport and browser access#

  • HTTPS. The API and the Anythink dashboard are served over HTTPS, so tokens, keys and data are encrypted in transit.
  • CORS through Allowed Application URLs. Browsers can call your project from the addresses listed under Settings › Organisation Settings › Allowed Application URLs, from Anythink's own domains, and from localhost while you develop. Add each web app's address, for example https://app.example.com or *.example.com. The same list controls which redirect addresses social sign-in accepts. See Customise the Anythink dashboard.
  • Rate limits. Requests are rate limited per project and client, and return 429 when a limit is reached. See Limits and quotas.

Your responsibilities#

Anythink enforces the checks above. How tightly they protect your data depends on how you configure your project.

  • Give roles the least they need. Create a role for your app's users with only the entity permissions they use. Don't give them Standard User: it's meant for your team and includes platform permissions such as managing entities and secrets. Keep Admin User for the people who run the project.
  • Scope and expire API keys. One key per job, the smallest set of permissions that works, and the shortest expiry you can live with.
  • Rotate keys and secrets. Create the replacement, deploy it, then revoke the old key or update the secret. Revoke a key straight away if it appears in a log, a commit or a screenshot.
  • Keep keys and secrets out of client apps. Never put an API key or a secret in browser code, a mobile app or a repository. Your apps should sign users in and call the API with the user's token, so roles and RLS apply per person.
  • Keep row-level security on for user data. Turn on RLS for any entity holding data that belongs to individual users or teams, ideally before your app writes to it. Test as a standard user, because administrators see everything.
  • Filter in workflows. Workflow steps read every record. When a workflow acts for one user, filter to that user in the step, and set access on records it creates.
  • List only your own addresses. Keep Allowed Application URLs to the apps you run, and remove ones you no longer use.
  • Separate your environments. Use different projects for development, staging and production, each with its own keys and secrets.

Check your own project#

Review who can do what in your project: roles and their permissions, which role each user has, your API keys, and which entities have row-level security on.

In the Anythink dashboard

  1. Open Settings › Users and select the Roles & Permissions tab. Check each role's API Access and open a role to review its permissions. Only project administrators see this tab.
  2. On the Users list, check which role each user has, and that only the people who run the project are on Admin User.
  3. Open My Account and select the API Keys tab. Review each key's permissions with View Permissions, and revoke keys you no longer use. You see the keys you created.
  4. Open Settings › Data Model. Entities with row-level security on show an RLS badge. Edit an entity to turn on Enable Row-Level Security.
  5. Open Settings › Organisation Settings. Check Enable group-level row access under Access Controls if you use groups, and review Allowed Application URLs.

With the CLI

bash
anythink roles list
anythink roles permissions list 104
anythink users list
anythink api-keys list
anythink entities list
  • roles list shows each role's ID. Pass an ID to roles permissions list to see the actions that role holds on each entity and anythink_ resource.
  • users list shows each user's role.
  • api-keys list shows your keys' names, permission counts, expiry dates and status. It never shows key values.
  • entities list has an RLS column showing which entities have row-level security on.

With an AI assistant (MCP)

text
Review the security of this project: list the roles and the permissions each one holds, which role each user has, my API keys with their expiry dates, and which entities don't have row-level security turned on.

The assistant runs roles list, roles permissions list, users list, api-keys list and entities list through the cli tool and summarises them. It sees key metadata only, never key values.

Next steps#