Dr. Estera Kot

FabCon Europe 2026 in 18 demos · Part 5 of 18 · Reading Fabric data from outside Fabric

OneLake Table Read API: REST reads that respect row security

An app reads a lakehouse table over REST, gets Apache Arrow back, and sees only the rows and columns OneLake security allows.

By Dr. Estera Kot, Microsoft MVP, CTO at Clouds on Mars, and former Microsoft Principal Product Manager for the Apache Spark runtime in Fabric. Published .

The OneLake Table Read API is a REST endpoint that returns rows from a Delta Lake or Apache Iceberg table in OneLake as Apache Arrow streams. It enforces OneLake authorization, row-level security (RLS), and column-level security (CLS) for the identity behind the bearer token. Your app receives only the rows and columns that identity may see, with no Spark cluster, no SQL endpoint, and no copy of the data.

Before this API, an app outside Fabric either ran a query engine or copied the data out and rebuilt the security rules. This API is a third option, one of the doors covered in FabCon Europe 2026 in 18 demos.

In short

  1. One POST /read opens a session over one snapshot of the table. One GET /readStream per stream returns Apache Arrow batches.
  2. OneLake security filters rows and columns on the server, for the caller's identity. A table or column the caller cannot see comes back as not found.
  3. The API is in public preview. Each POST /read is billed by rows scanned, not rows returned.
A terminal sends one POST /read for four columns of the synthetic preference_trials table and gets back one Apache Arrow stream with seven rows. 14 seconds, no sound, recorded Oct 21, 2026.

Same demo in Polish and German. Step-by-step runbook: D05.

What the OneLake Table Read API is and how it works

The API runs on onelake.table.fabric.microsoft.com, the same host as the catalog endpoints in Unity Catalog and Iceberg REST on OneLake. It accepts a user or service principal token for the OneLake audience, https://storage.azure.com. The first call opens a read session and names the columns:

POST https://onelake.table.fabric.microsoft.com/v1.0/workspaces/<WorkspaceID>/items/<ItemID>/schemas/<SchemaName>/tables/<TableName>/read
Authorization: Bearer <token for https://storage.azure.com>
Content-Type: application/json

{"columns": ["formula_id", "panel_segment", "n_testers", "first_choice_pct"]}

The response lists opaque stream identifiers. The second call runs once per identifier and returns an Apache Arrow IPC stream:

GET https://onelake.table.fabric.microsoft.com/v1.0/workspaces/<WorkspaceID>/items/<ItemID>/schemas/<SchemaName>/tables/<TableName>/readStream/<StreamID>
Authorization: Bearer <same token>

Every stream carries the same snapshot, even if a pipeline writes mid-read. Large results split into several streams that download in parallel. The session expires after 60 minutes.

The filtering happens on the server. OneLake checks the token's identity against OneLake security before your app reads a single batch. For RLS, the API materializes the filtered result in a hidden OneLake location. Rows the caller may not see never enter a stream, so your app never rebuilds the rules.

Request path of the OneLake Table Read API Your app gets an Entra ID token for storage.azure.com and sends POST read to the OneLake table endpoint. OneLake security checks authorization, RLS, and CLS for the token's identity before it touches the Delta or Iceberg table. The read session holds one snapshot split into streams. The app calls GET readStream once per stream and receives Apache Arrow record batches with only the allowed rows and columns. Your app or agent OneLake table endpoint Outside Fabric onelake.table.fabric.microsoft.com, operated by Microsoft 1. Entra ID token audience storage.azure.com 2. POST …/read names the columns billed by rows scanned 3. OneLake security authorization, RLS, CLS for the token's identity Delta or Iceberg table in OneLake preference_trials Filtering happens here, on the server. Hidden rows never enter a stream. 4. Read session one snapshot, one or more streams 5. GET …/readStream/{id} once per stream, within 60 minutes Apache Arrow IPC stream 6. Record batches only the allowed rows and columns Request path of the OneLake Table Read API Six steps from top to bottom. Your app gets a token, sends POST read, OneLake security filters for the token's identity, the table is read into a session with one snapshot, the app calls GET readStream per stream, and Arrow record batches arrive with only the allowed rows and columns. OneLake, operated by Microsoft Your app or agent 1. Entra ID token audience storage.azure.com 2. POST …/read, names the columns billed by rows scanned 3. OneLake security authorization, RLS, CLS for the token's identity, on the server Delta or Iceberg table preference_trials in OneLake 4. Read session one snapshot, one or more streams 5. GET …/readStream/{id} once per stream, within 60 minutes 6. Apache Arrow record batches only the allowed rows and columns Hidden rows never enter a stream.
Figure 1. The request path. OneLake security sits between the POST and the table, so the filtering happens on the server, before step 4. Your app only ever sees what the token's identity may see.

What the demo shows

The clip is a real call against lh_oud_rd, the synthetic lakehouse of a made-up oud perfume house.

The clip proves server-side column projection with no engine on the client. It does not show a restricted caller, because the demo identity could read the whole table.

To see RLS at work, add a role with a row filter, as in OneLake security: define RLS and CLS once, and call as a member of that role. Do not test as an admin: per Learn, workspace Admin, Member, and Contributor roles are not restricted by RLS or CLS.

Terminal output: POST /read returned 1 stream, Apache Arrow, 7 rows, with columns formula_id, panel_segment, n_testers, first_choice_pct, followed by seven rows for formulas OB-101 to OB-106.
Still at 0:10. One POST /read, one Arrow stream, seven rows, four columns. The table has nine.

When to use the Table Read API instead of Iceberg REST or the SQL endpoint

Three doors read Fabric tables from outside. They differ in who runs the query and who applies OneLake security.

IDDoorReturnsRLS and CLSUse it when
W1Table Read APIArrow rowsFiltered by OneLake, per callerAn app needs rows without running an engine
W2Iceberg REST or Unity Catalog APIMetadata. Your engine reads the files.Not filtered. Restricted users are blocked.An external engine queries in place
W3SQL analytics endpointT-SQL resultsFiltered in user's identity access modeA BI tool needs joins and aggregates

The Table Read API returns rows, not answers: one sum over a million rows means scanning and downloading all of them. Full comparison: Unity Catalog and Iceberg REST on OneLake.

Limits and catches of the Table Read API

The catch: it is a public preview, billed by rows scanned, not rows returned. Learn's read page says "You're billed for the POST /read operation," and its consumption page says "Calls to the table read API are billed to the calling user." Each POST /read costs 8 CU seconds per million rows scanned, rounded up to the next million. RLS can scan far more rows than it returns.

The hidden copy of RLS-filtered results is billed as storage for seven days. Four more behaviors trip up client code:

IDCallerResponseWhat the app sees
O1Can read the whole table, as in the demoArrowEvery row
O2RLS allows some rowsArrowOnly the allowed rows
O3CLS hides a column, wildcard requestArrowHidden column gone, no error
O4RLS allows no rowsSuccessEmpty Arrow response
O5Names a column CLS hidesNot foundThe request fails
O6No permission on the tableNot foundAs if the table did not exist
Figure 2. Six callers, six answers, decided on the server. O1 is the demo. O2 to O6 follow Microsoft Learn.

Run the Table Read API demo yourself

You need a test tenant, the Azure CLI signed in with az login, Python 3.9 or later with requests and pyarrow, and the tables that python3 fabdemo.py up from the recap repo loads into lh_oud_rd. Then run:

python3 fabdemo.py table-read preference_trials formula_id,panel_segment,n_testers,first_choice_pct

Expected result: one Arrow stream with the seven preference trials and only the four requested columns. Time and cost: about 1 minute. Runbook D05 says each POST /read is "billed to the capacity," which differs from Learn's "billed to the calling user," and Learn's wording is what counts. Full steps: runbook D05.

The script takes its token from az account get-access-token --resource https://storage.azure.com and opens each stream with pyarrow.ipc.open_stream. It omits the /schemas/<SchemaName>/ segment, which the demo lakehouse accepted. Use the documented route in new code.

What to do on Monday

On Monday: Pilot the Table Read API for apps that copy data out of Fabric today.

A copy that feeds an app costs twice: once for the copy, once for its second set of security rules. Pilot one app on one table and test as a role member.

Key facts at a glance

Checked on Microsoft Learn on November 3, 2026.

IDFactSource
K1Status: public previewLearn: Read OneLake table data
K2Host onelake.table.fabric.microsoft.com, token audience https://storage.azure.comLearn: OneLake table APIs
K3POST …/read, then GET …/readStream/{streamId} per stream, Apache Arrow IPCLearn: Read OneLake table data
K4Delta Lake and Apache Iceberg tables, one snapshot per sessionLearn: OneLake table APIs
K5OneLake authorization, RLS, and CLS per caller. Hidden tables and columns return not found.Learn: Read OneLake table data
K6Session expires after 60 minutes. No cross-region shortcuts.Learn: Read OneLake table data
K78 CU seconds per million rows scanned per POST /read, billed to the calling user. RLS results kept seven days.Learn: OneLake consumption

Frequently asked questions

What is the OneLake Table Read API?

The OneLake Table Read API is a REST endpoint in Microsoft Fabric that returns rows from a Delta Lake or Apache Iceberg table as Apache Arrow streams. The calling app needs no Spark cluster and no SQL endpoint.

Does the OneLake Table Read API enforce row-level security?

Yes. It enforces OneLake authorization, row-level security, and column-level security for the identity behind the bearer token, on the server. The app receives only the rows and columns that identity may see.

Is the OneLake Table Read API generally available?

No. Microsoft Learn lists the OneLake Table Read API as a public preview on November 3, 2026, and says features and behavior might change before general availability.

How much does the OneLake Table Read API cost?

Each POST /read to the OneLake Table Read API consumes 8 CU seconds per million rows scanned, rounded up to the next million. Microsoft Learn says calls are billed to the calling user, and downloading the streams carries no separate charge.

Why does the Table Read API return not found for a table that exists?

The caller has no permission on the table, or the request names a column that column-level security hides. Both cases return not found, so not found never proves that a table is missing.

About the author

Dr. Estera Kot is CTO at Clouds on Mars, a Microsoft and Databricks partner for data and AI in Europe and the Middle East. At Microsoft she was Principal Product Manager for the Apache Spark runtime in Azure Synapse Analytics and Microsoft Fabric, and she created the Native Execution Engine. She is a Microsoft MVP and holds a Ph.D. in Computer Science from the Warsaw University of Technology. She presented this series as the FabCon Europe 2026 recap in Gdynia on October 21, 2026, and online on October 23, 2026. Slides, recordings, and runbooks are in the public recap repository.

Sources

Microsoft Learn and the Microsoft Fabric blog, checked on November 3, 2026.