Connections
Give Rayfin functions app-identity tokens for Fabric SQL, OneLake, Fabric REST, Azure AI Foundry, and Azure DevOps.
Use a function connection when server-side code needs to call an external Azure or Fabric resource. In deployed Functions, these external calls use application authentication: Rayfin supplies resource-scoped tokens for the Fabric app identity through ctx.Tokens.
Note
Functions and function connections are generally available in Rayfin 1.36 and are not available in every Fabric region or tenant.
Declare audiences in RayfinContext
Add the resource audience as the second generic parameter of RayfinContext, then read the token from ctx.Tokens:
import {
AudienceType,
UserDataFunctions,
type RayfinContext,
} from '@microsoft/fabric-user-data-functions';
export type AppSchema = Record<string, never>;
const udf = new UserDataFunctions();
udf.func(
'checkFabricAccess',
async (
ctx: RayfinContext<AppSchema, AudienceType.Fabric>,
): Promise<string> => {
const token = ctx.Tokens.Fabric;
return token.length > 0 ? 'ready' : 'missing';
},
[],
);The annotation is the declaration. Keep the third argument to udf.func() as [].
Supported audiences
AudienceType in 1.36.2 contains only these members. Changed in 1.36
| Audience | Use for |
|---|---|
AudienceType.Sql | Fabric Lakehouse SQL analytics, Warehouse, SQL Database, Mirrored Database, and Azure SQL. |
AudienceType.Storage | Fabric OneLake files and Azure Blob, Table, or Queue Storage. |
AudienceType.Fabric | Microsoft Fabric REST APIs. |
AudienceType.AzureAI | Azure AI Foundry endpoints. |
AudienceType.ADO | Azure DevOps APIs. |
CosmosDB, KeyVault, EventGrid, Kusto, and WorkIQ are not public AudienceType members in 1.36.2. A Power BI semantic model is not reached through function connections; use the fabric-semanticmodel connector instead.
Tokens are typed and bounded
ctx.Tokens exposes only declared audiences:
async (
ctx: RayfinContext<AppSchema, AudienceType.Sql | AudienceType.Storage>,
) => {
const sqlToken = ctx.Tokens.Sql;
const storageToken = ctx.Tokens.Storage;
return { sqlTokenLength: sqlToken.length, storageTokenLength: storageToken.length };
};A direct read of a declared-but-unminted token throws:
No token available for audience '<Audience>'. Ensure a connection with this audience type is declared.Declaring an audience does not grant resource permissions. Grant the external resource to the Fabric app identity. For current Fabric apps, that identity is the owner of the Fabric app item.
Rayfin data remains caller-scoped
services.functions.auth.type: application does not make ctx.getDataClient() use the app identity. Rayfin DB access uses the invocation's Rayfin token and preserves the signed-in caller's data permissions.
| Code path | Identity |
|---|---|
ctx.getDataClient() | Signed-in caller. |
ctx.Tokens.Sql, ctx.Tokens.Storage, ctx.Tokens.Fabric, ctx.Tokens.AzureAI, ctx.Tokens.ADO | Fabric app identity. |
Wrap a token for Azure SDK clients
Many Azure SDK clients expect a TokenCredential. Wrap the context token:
import type { AccessToken, TokenCredential } from '@azure/identity';
export class ContextTokenCredential implements TokenCredential {
constructor(private readonly token: string) {}
async getToken(): Promise<AccessToken> {
return { token: this.token, expiresOnTimestamp: Date.now() + 3600_000 };
}
}Find Fabric resource coordinates
Every connection needs a real endpoint. Resolve Fabric coordinates from the Fabric portal, a Fabric CLI/MCP tool when one is already available, or the Fabric REST API. Do not guess endpoints or use process.env as the primary source for resource coordinates.
| You need | Fabric item | Where to read it |
|---|---|---|
| Lakehouse SQL server | Lakehouse | properties.sqlEndpointProperties.connectionString from GET /workspaces/{workspaceId}/lakehouses/{lakehouseId}. |
| Lakehouse OneLake path | Lakehouse | properties.oneLakeFilesPath or properties.oneLakeTablesPath from the same Lakehouse GET. |
| Warehouse SQL server | Warehouse | properties.connectionString from GET /workspaces/{workspaceId}/warehouses/{warehouseId}. |
| SQL Database server and database | SQL Database | properties.serverFqdn and properties.databaseName from GET /workspaces/{workspaceId}/sqlDatabases/{sqlDatabaseId}. |
| Item GUID | Any item | id from GET /workspaces/{workspaceId}/items?type={Type}. |
Authoring-time lookup is separate from runtime access. Use your developer credentials to look up coordinates while writing the function; at runtime the deployed function uses ctx.Tokens.<Audience> from the app identity.
Call Fabric SQL
All Fabric SQL resources share the same requirements:
- Install
mssql@^12.6.0in the functions package. That version pulls atediousrelease with the Fabric LOGIN7 fixes. - Use
encrypt: true, notencrypt: 'strict'. - Use
azure-active-directory-access-tokenwithctx.Tokens.Sql. - Ask for the actual SQL endpoint and database or item GUID from Fabric. Do not invent endpoints.
| Resource | What to ask for | database value |
|---|---|---|
| Lakehouse SQL analytics | SQL analytics endpoint and item GUID from the Fabric portal | Item GUID |
| Warehouse | SQL endpoint and item GUID from the Fabric portal | Item GUID |
| SQL Database | Full connection string from the Fabric portal | Database name from the connection string |
| Mirrored Database | SQL analytics endpoint and item GUID from the Fabric portal | Item GUID |
For Lakehouse, Warehouse, and Mirrored Database connections, pass the Fabric item GUID as database. Multi-item workspaces cannot route the connection reliably without it.
import sql from 'mssql';
import {
AudienceType,
UserDataFunctions,
type RayfinContext,
} from '@microsoft/fabric-user-data-functions';
export type AppSchema = Record<string, never>;
const udf = new UserDataFunctions();
const SQL_SERVER = '<endpoint>.datawarehouse.fabric.microsoft.com';
const DATABASE = '<item-guid-or-database-name>';
udf.func(
'queryWarehouse',
async (
ctx: RayfinContext<AppSchema, AudienceType.Sql>,
query: string,
): Promise<Record<string, unknown>[]> => {
const pool = await sql.connect({
server: SQL_SERVER,
database: DATABASE,
options: { encrypt: true, trustServerCertificate: false },
authentication: {
type: 'azure-active-directory-access-token',
options: { token: ctx.Tokens.Sql },
},
});
const result = await pool.request().query(query);
await pool.close();
return result.recordset;
},
[],
);Call OneLake files
Use AudienceType.Storage for OneLake DFS URLs.
For OneLake, ask for the file URL from the Fabric portal: Lakehouse → file → Properties → URL. It has this shape:
https://onelake.dfs.fabric.microsoft.com/<workspaceId>/<itemId>/Files/<path>A OneLake example:
import {
AudienceType,
UserDataFunctions,
type RayfinContext,
} from '@microsoft/fabric-user-data-functions';
export type AppSchema = Record<string, never>;
const udf = new UserDataFunctions();
udf.func(
'readOneLakeFile',
async (
ctx: RayfinContext<AppSchema, AudienceType.Storage>,
fileUrl: string,
): Promise<string> => {
const response = await fetch(fileUrl, {
headers: { Authorization: ['Bearer', ctx.Tokens.Storage].join(' ') },
});
if (!response.ok) {
throw new Error(`OneLake read failed: ${response.status}`);
}
return await response.text();
},
[],
);Call Fabric REST APIs
Use AudienceType.Fabric for Microsoft Fabric REST APIs.
Grant the app identity access to the workspace, item, or Fabric API you call. Check the specific API because not every Fabric endpoint supports application identities.
import {
AudienceType,
UserDataFunctions,
type RayfinContext,
} from '@microsoft/fabric-user-data-functions';
export type AppSchema = Record<string, never>;
const udf = new UserDataFunctions();
const FABRIC_API = 'https://api.fabric.microsoft.com/v1';
udf.func(
'listWorkspaceItems',
async (
ctx: RayfinContext<AppSchema, AudienceType.Fabric>,
workspaceId: string,
): Promise<unknown> => {
const response = await fetch(`${FABRIC_API}/workspaces/${workspaceId}/items`, {
headers: { Authorization: ['Bearer', ctx.Tokens.Fabric].join(' ') },
});
if (!response.ok) {
throw new Error(`Fabric API returned ${response.status}`);
}
return await response.json();
},
[],
);Call Azure Blob Storage
Use AudienceType.Storage for Azure Blob, Table, or Queue Storage.
Grant the app identity the Azure Storage data role required by your operation, such as Storage Blob Data Reader for listing and reading blobs or Storage Blob Data Contributor for writes. Install SDK packages in the functions package:
cd rayfin/functions
npm install @azure/storage-blob @azure/identityimport { BlobServiceClient } from '@azure/storage-blob';
import {
AudienceType,
UserDataFunctions,
type RayfinContext,
} from '@microsoft/fabric-user-data-functions';
import { ContextTokenCredential } from './ContextTokenCredential.js';
export type AppSchema = Record<string, never>;
const udf = new UserDataFunctions();
udf.func(
'listBlobContainers',
async (
ctx: RayfinContext<AppSchema, AudienceType.Storage>,
accountUrl: string,
): Promise<string[]> => {
const credential = new ContextTokenCredential(ctx.Tokens.Storage);
const service = new BlobServiceClient(accountUrl, credential);
const names: string[] = [];
for await (const container of service.listContainers()) {
names.push(container.name);
}
return names;
},
[],
);Pass an account URL such as https://<account>.blob.core.windows.net.
Call Azure AI Foundry
Use AudienceType.AzureAI for Azure AI Foundry or Azure OpenAI APIs.
Grant the app identity the role required by the Azure AI resource and API. Use the endpoint from Azure AI Foundry or the Azure portal, then send the token as a bearer token. Fill in the path and body for the specific API you call.
import {
AudienceType,
UserDataFunctions,
type RayfinContext,
} from '@microsoft/fabric-user-data-functions';
export type AppSchema = Record<string, never>;
const udf = new UserDataFunctions();
const AI_ENDPOINT = 'https://<resource>.services.ai.azure.com';
udf.func(
'callAzureAi',
async (
ctx: RayfinContext<AppSchema, AudienceType.AzureAI>,
prompt: string,
): Promise<unknown> => {
const response = await fetch(`${AI_ENDPOINT}/<api-path>`, {
method: 'POST',
headers: {
Authorization: 'Bearer ' + ctx.Tokens.AzureAI,
'Content-Type': 'application/json',
},
body: JSON.stringify({ prompt }),
});
if (!response.ok) {
throw new Error(`Azure AI returned ${response.status}`);
}
return await response.json();
},
[],
);Call Azure DevOps
Use AudienceType.ADO for Azure DevOps REST APIs.
Grant the app identity access to the Azure DevOps organization, project, and resource you call. Provide the organization URL, such as https://dev.azure.com/<org>.
import {
AudienceType,
UserDataFunctions,
type RayfinContext,
} from '@microsoft/fabric-user-data-functions';
export type AppSchema = Record<string, never>;
const udf = new UserDataFunctions();
const ADO_ORG = 'https://dev.azure.com/<org>';
udf.func(
'listAdoProjects',
async (ctx: RayfinContext<AppSchema, AudienceType.ADO>): Promise<unknown> => {
const response = await fetch(`${ADO_ORG}/_apis/projects?api-version=7.1`, {
headers: { Authorization: ['Bearer', ctx.Tokens.ADO].join(' ') },
});
if (!response.ok) {
throw new Error(`Azure DevOps returned ${response.status}`);
}
return await response.json();
},
[],
);Rules
- Declare generic audiences in the
RayfinContextannotation and read tokens fromctx.Tokens.<Audience>. - Keep the third argument to
udf.func()as[]in new code. - Use real endpoints from Fabric or Azure. Do not use
process.envas the primary source for resource coordinates. - Never return
ctx.Tokens.*values to the frontend. - Grant external resource access to the Fabric app identity before testing deployed functions.
- Install resource SDK packages in the functions package, not the project root.
Migrate from udf.connection() and ctx.getToken()
udf.connection({ audienceType }) and ctx.getToken(audienceType) still work at runtime, but they no longer give the preferred type-safe authoring model. Move the audience into the context annotation and read ctx.Tokens. Deprecated in 1.36
// Before
udf.func(
'before',
async (ctx: RayfinContext): Promise<string> => {
return ctx.getToken(AudienceType.Sql);
},
[udf.connection({ audienceType: AudienceType.Sql })],
);
// After
udf.func(
'after',
async (ctx: RayfinContext<AppSchema, AudienceType.Sql>): Promise<string> => {
return ctx.Tokens.Sql;
},
[],
);Both halves matter: the annotation registers the binding and narrows ctx.Tokens.
Local token identity
During npx rayfin dev and npx rayfin dev functions apply, external-resource tokens use the account the local Functions host signs in with. Deployed Functions use the application identity. Test deployed permissions even if local debugging works.
In my Rayfin project, add a function connection to <Fabric SQL, OneLake, Fabric REST, Azure AI Foundry, or Azure DevOps>.
Use Rayfin 1.36 style. Declare the audience in the handler's context type, for example `RayfinContext<AppSchema, AudienceType.Sql>`, and read the token from `ctx.Tokens.Sql`. Keep the third argument to `udf.func()` as `[]`. Do not use `ctx.getToken()` or `udf.connection({ audienceType })` in new code. Use real resource endpoints from Fabric or Azure; do not invent URLs. Install resource SDK packages in rayfin/functions/package.json. Explain which identity must be granted access in deployed Functions and how local development differs.Secrets in functions
Declare Rayfin secrets with the CLI, read them as typed ctx.Secrets properties, and supply local values through local.settings.json.
Calling functions from your app
Invoke Rayfin functions from the frontend with RayfinClient, AppFunctionsSchema, per-call options, and local Vite routing.