Data access
The principle
Section titled “The principle”A published app never contains data. For a source registered db-delegated (the default, and the only mode Azure SQL Database supports), it contains code that fetches data at view time, authenticated as the person viewing. Not as the builder, not as a service account, not as the platform.
A source can instead be registered gateway-enforced: an explicit, audited opt-out where a service identity reads the source and the gateway filters per viewer above the database, rather than the database authenticating the viewer directly. Today that applies only to Fabric Warehouse and lakehouse sources (fabric-dw), and only read-only. Every registration in this mode is logged; see Expose a database for what the enforcement badge means and why the mode is a recorded, visible choice rather than a default anyone falls into by accident.
This one decision does most of sprig’s security work:
- Sharing an app shares nothing. When Ops approves sharing with a team, team members can open the app. For a db-delegated source, each of them then sees only what their own database permissions return: an analyst covered by row-level security scoped to one region sees one region. For a gateway-enforced source, sharing still grants only what the reader-group mapping Ops configured allows; there is no source-side row-level security to fall back on there, because the source itself sees the shared serving identity, never the viewer.
- Revocation keeps working, for either enforcement mode. Remove someone’s group membership and every sprig app goes dark for them at their next query. There is no cached copy, no snapshot, no export to chase.
- No new data governance surface, for a db-delegated source. Your existing Entra groups and the source database’s own permissions are the data authorization layer there; sprig adds no parallel ACL system to maintain or audit. A gateway-enforced source is the recorded exception: its own permissions apply to the shared serving identity, not the viewer, so the reader-group mapping enforced by sprig’s own gateway/data-API policies is the authorization boundary for that source instead. Either way, Ops configures access once, at expose time, not per app.
How it works technically
Section titled “How it works technically”Every app’s data calls go to the same place: the gateway, same-origin, at /data/*, whether
the app is still a draft being built or fully published and open to viewers. For a
db-delegated source, the gateway validates the caller’s own token, forwards it
on-behalf-of to a shared Data API builder instance, which in turn exchanges it for a
database-scoped token before running the query. The database authenticates the actual
caller, not a service account and not the gateway itself; row-level security and
permissions are evaluated exactly as if that person had connected directly.
For a gateway-enforced source, the database instead authenticates a service identity, and the gateway and the data API’s own policies do the per-viewer filtering above it. Every registration in this mode writes an audit event stating plainly that authorization is enforced at the gateway, not in the database, so the difference is a recorded fact about that source, not a silent downgrade.
This is a deliberate change from an earlier design where the browser called a source API directly with no sprig component in between. That “no middle tier” shape didn’t survive contact with the flat-cost model and the OAuth mechanics a remote MCP connector needs: the gateway is now a required part of every data read. For a db-delegated source, the identity on the query is still always the viewer’s, never a shared credential, and the gateway holds no standing data access of its own there; it only ever forwards a token it just validated. The gateway is a single, reviewable, always-audited choke point for every query, not a store: it streams responses through and caches nothing.
What builders and viewers need
Section titled “What builders and viewers need”- Ops registers a corporate data source (an existing Azure SQL Database, Fabric Warehouse, or lakehouse SQL analytics endpoint), then exposes specific tables and columns read-only, mapped to specific Entra groups. Fabric Warehouse tables that declare a primary key can be exposed when Fabric support was enabled during installation. Fabric lakehouse SQL analytics endpoints can be registered and discovered under the same prerequisite, but their keyless tables cannot be exposed yet. See Supported data sources for the current support matrix and Expose a database for the Ops workflow. Nothing is reachable through sprig until Ops exposes it.
- An onboarded builder can instead ask Claude to provision an Azure SQL database for their own app and choose its entities and read/write actions. This path does not require Ops to register or expose the database. See Publishing and sharing.
- For an Ops-exposed source, the builder needs to be in a group Ops mapped to that source.
What
list_sourcesdoesn’t show doesn’t exist for them: exclusions are invisible, not forbidden-looking. - Each viewer needs their own membership in whatever group governs the data the app queries. No membership → for a db-delegated source, the database returns nothing for their queries; for a gateway-enforced source, the gateway/data-API policy does. Either way, this is the designed behaviour: an app can never be a way around your data permissions.
What sprig refuses to do
Section titled “What sprig refuses to do”Every published app is gateway-authenticated by construction: there’s no per-app opt-out of sign-in to reject, because the gateway’s own OIDC session and group check front every app the same way. What Claude is instructed never to do is bake query results into the app’s own artifact. The honest limitation: a determined builder could still hand-paste data into HTML, the same way they could paste it into an email. What sprig removes is the systemic pattern where copying data is the only way to share an app.