Rayfin

Delegated and application access

Which identity each server-side Rayfin surface uses — the signed-in user or the app — and what access to grant at each data source.

Server-side Rayfin code reaches three kinds of data: entities your app owns, data that already lives in Fabric (through connectors), and other Microsoft resources (through function connections). Every one of those calls runs as one of two identities:

  • Delegated — the signed-in user. Rayfin starts from the user's Microsoft Entra ID session (Fabric SSO, direct Entra token sign-in, or an embed host) and acts on that user's behalf. The source decides what that user may read and write.
  • Application — the app itself. For current Fabric apps, the app identity is the owner of the Fabric app item. Every user of the app gets the same access, so the app identity — not each user — needs permission on the source.

Changed in 1.36

Rayfin 1.36 moved two surfaces to the app identity. Function connections now run only as the app identity, and rayfin connector add configures SQL connectors to run as the app identity. In 1.35, both ran as the signed-in user.

Which identity each surface uses

SurfaceYou declareRuns as, once deployedWho needs access at the source
Your own data from the browser — client.data.<Entity>@role() / @authenticated() policies on the entitySigned-in userNobody — entity policies decide
Your own data from a function — ctx.getDataClient()The same entity policiesSigned-in callerNobody — entity policies decide
Function connections — ctx.Tokens.<Audience>RayfinContext<Schema, AudienceType.X> and services.functions.auth.type: applicationApp identityThe app identity
SQL connectors — warehouse, SQL database, Lakehouse SQL endpointauth.type in rayfin.yml; connector add writes applicationApp identity, or the signed-in user with delegatedThe app identity, or each user
Semantic model connectorsauth.type: delegated (the only allowed value)Signed-in userEach user

Your own data always runs as the caller

Entities in rayfin/data/ are protected by permission decorators. A policy callback compares the caller's claims to fields on each row, so client.data.<Entity> returns only the rows that caller may see.

The same is true inside a function. ctx.getDataClient() uses the invocation's Rayfin token, so entity policies apply to the user who invoked the function. Setting services.functions.auth.type: application does not switch your Rayfin data to the app identity.

Function connections run as the app

Since Rayfin 1.36, enabled Functions must declare application authentication:

rayfin/rayfin.yml
services:
  functions:
    enabled: true
    auth:
      type: application

A deployed function that declares an audience on its RayfinContext receives a token for the app identity in ctx.Tokens. In this function, the Rayfin data query runs as the caller, and the Fabric REST call runs as the app:

rayfin/functions/src/function_app.ts
import {
  AudienceType,
  UserDataFunctions,
  type RayfinContext,
} from '@microsoft/fabric-user-data-functions';

export type AppSchema = {
  Todo: { id: string; title: string };
};

const udf = new UserDataFunctions();

udf.func(
  'todoCountAndWorkspaceCount',
  async (
    ctx: RayfinContext<AppSchema, AudienceType.Fabric>,
  ): Promise<{ todos: number; workspaces: number }> => {
    // Runs as the signed-in caller: the Todo entity's policies apply.
    const todos = await ctx.getDataClient().Todo.select(['id']).execute();

    // Runs as the app identity: it must have access in Fabric.
    const response = await fetch('https://api.fabric.microsoft.com/v1/workspaces', {
      headers: { Authorization: `Bearer ${ctx.Tokens.Fabric}` },
    });
    if (!response.ok) {
      throw new Error(`Fabric API returned ${response.status}`);
    }
    const body = (await response.json()) as { value: unknown[] };

    return { todos: todos.length, workspaces: body.value.length };
  },
  [],
);

Grant the app identity the permission each resource needs — for example a workspace role for Fabric REST calls, or a data-plane role for Azure Storage — and check that the Fabric API you call supports application identities. Connections lists the five supported audiences and what to grant for each.

Signing in to the app and being allowed to invoke a function work as before; application authentication only changes which identity the function uses for external resources.

Warning

During local development, the Functions host started by rayfin dev gets tokens for the account you signed in with, not for the app identity. A call that works on your machine can fail after rayfin up if the app identity lacks access. Grant the app identity access before you deploy.

Connectors choose per connector

Each connector entry in rayfin.yml carries its own auth.type:

  • delegated runs every query as the signed-in user, through an on-behalf-of token exchange. The user needs their own permission on the Fabric workspace and item, and @role() policies on generated connector entities can compare claims to the caller.
  • application runs every query as the app identity. All users see the same data, so claims-based policies no longer distinguish users. It is allowed only for fabric-sqlanalytics, fabric-warehouse, and fabric-sqldatabase.

rayfin connector add writes auth.type: application for those three SQL types. To keep per-user access, change the value to delegated before you deploy — and again after you re-add the connector, because re-adding resets it. Semantic model connectors accept only delegated. See Connector authentication.

Grant access at the source

Neither identity grants access by itself. Rayfin passes the identity through, and the target resource decides:

  1. For delegated calls, give each user — or a group they belong to — access to the Fabric workspace and item. A user without access gets an authorization error.
  2. For application calls, give the app identity — the owner of the Fabric app item — access to the resource.
  3. For your own entities, write permission decorators. No source grant is involved.

Choose a surface

You needUse
Per-user rows from entities your app ownsEntity policies on your own data
Per-user rows from an existing warehouse or SQL databaseA SQL connector with auth.type: delegated
One shared view of an existing Fabric sourceA SQL connector with auth.type: application
DAX over a semantic model, scoped to each userA semantic model connector
Custom server-side calls to Fabric, OneLake, Azure Storage, Azure AI Foundry, or Azure DevOpsA function connection
Any other HTTPS APIA function that reads an API key from ctx.Secrets
PromptChoose the identity for a Rayfin integration
In my Rayfin project, help me decide which identity each server-side integration should use, then configure it. For data my app owns in rayfin/data, keep access caller-scoped with @role() or @authenticated() policies — this also applies to ctx.getDataClient() inside functions. For an existing Fabric warehouse, SQL database, or Lakehouse SQL endpoint, add a connector and set auth.type in rayfin/rayfin.yml: delegated when each user should see only what they are allowed to see at the source, application when every user should see the same data through the app identity. Semantic model connectors must use delegated. For custom calls to Fabric REST, OneLake, Azure Storage, Azure AI Foundry, or Azure DevOps, write a function that declares the audience on RayfinContext and reads ctx.Tokens, with services.functions.auth.type: application in rayfin.yml — those calls run as the app identity, which is the owner of the Fabric app item. Tell me exactly which permissions to grant to which identity on each resource, and which files you changed.
Something wrong on this page?Report an issueEdit this page

On this page