@microsoft/rayfin-guide 1.36.0-alpha.1620 → 1.36.0-alpha.1675
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/docs/app-backend/deploy.md +57 -11
- package/assets/docs/auth/direct-entra-auth.md +139 -0
- package/assets/docs/auth/external-embed-host.md +131 -0
- package/assets/docs/auth/fabric.md +13 -5
- package/assets/docs/auth/index.md +6 -0
- package/assets/docs/cli/connectors/index.md +4 -0
- package/assets/docs/cli/connectors/invoke.md +28 -0
- package/assets/docs/cli/index.md +22 -0
- package/assets/docs/cli/templates.md +4 -5
- package/package.json +1 -1
|
@@ -62,6 +62,30 @@ npx rayfin up
|
|
|
62
62
|
|
|
63
63
|
If you are not signed in, the CLI launches an interactive login flow automatically.
|
|
64
64
|
|
|
65
|
+
### Choose a unique Fabric item name
|
|
66
|
+
|
|
67
|
+
By default, `rayfin up` uses the project ID from `rayfin.yml` as the Fabric item name.
|
|
68
|
+
Pass `--item-name` to deploy a template under a different name without editing its configuration:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
npx rayfin up --item-name my-team-todo-app
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
The override changes only the Fabric item display name.
|
|
75
|
+
Runtime settings and service configuration continue to come from `rayfin.yml`.
|
|
76
|
+
Rayfin records the effective item name and item ID in `rayfin/.deployments.json`, so later deployments continue targeting the same item.
|
|
77
|
+
|
|
78
|
+
For an agent or CI pipeline, provide explicit workspace targeting and structured output:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
npx rayfin up \
|
|
82
|
+
--item-name my-team-todo-app \
|
|
83
|
+
--workspace-id <workspace-guid> \
|
|
84
|
+
--output json
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Do not pass `--yes` unless reusing an existing same-named item is intentional.
|
|
88
|
+
|
|
65
89
|
### What `rayfin up` does
|
|
66
90
|
|
|
67
91
|
The command performs these steps in order:
|
|
@@ -91,6 +115,7 @@ For frontend frameworks, the CLI also runs `rayfin env` to emit a framework-spec
|
|
|
91
115
|
"deployments": {
|
|
92
116
|
"myworkspace": {
|
|
93
117
|
"fabricItemId": "7db00cb9-f630-4ecf-8fc9-942e60af5d78",
|
|
118
|
+
"itemName": "my-team-todo-app",
|
|
94
119
|
"fabricApiUrl": "https://...",
|
|
95
120
|
"fabricWorkspaceId": "8b17cf64-3c12-46ac-a572-192732c32641",
|
|
96
121
|
"fabricTenantId": "...",
|
|
@@ -113,13 +138,13 @@ VITE_RAYFIN_PUBLISHABLE_KEY=pk-nua-EHihY2jz71V65YB4
|
|
|
113
138
|
VITE_FABRIC_PORTAL_URL=https://dxt.fabric.microsoft.com/
|
|
114
139
|
```
|
|
115
140
|
|
|
116
|
-
| Variable
|
|
117
|
-
|
|
|
118
|
-
| `VITE_FABRIC_ITEM_ID`
|
|
119
|
-
| `VITE_RAYFIN_API_URL`
|
|
120
|
-
| `VITE_FABRIC_WORKSPACE_ID`
|
|
141
|
+
| Variable | Description |
|
|
142
|
+
| ----------------------------- | ------------------------------------------------------------- |
|
|
143
|
+
| `VITE_FABRIC_ITEM_ID` | The Fabric item ID for this deployment. |
|
|
144
|
+
| `VITE_RAYFIN_API_URL` | Full URL to the deployed Rayfin backend API. |
|
|
145
|
+
| `VITE_FABRIC_WORKSPACE_ID` | The Fabric workspace ID containing the deployment. |
|
|
121
146
|
| `VITE_RAYFIN_PUBLISHABLE_KEY` | Publishable key used by the Rayfin client for authentication. |
|
|
122
|
-
| `VITE_FABRIC_PORTAL_URL`
|
|
147
|
+
| `VITE_FABRIC_PORTAL_URL` | URL to the Fabric portal for managing the deployment. |
|
|
123
148
|
|
|
124
149
|
### Authentication after deployment
|
|
125
150
|
|
|
@@ -203,6 +228,27 @@ Add `--json` for machine-readable output:
|
|
|
203
228
|
npx rayfin up status --json
|
|
204
229
|
```
|
|
205
230
|
|
|
231
|
+
To inspect a specific registered deployment instead of the active one, pass its name to `up`:
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
npx rayfin up --env-file staging status
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
If `RAYFIN_WORKSPACE_ID` is also set, the selected deployment must belong to that workspace.
|
|
238
|
+
|
|
239
|
+
The management endpoint check verifies authenticated access to the deployed Fabric item and retrieves its publishable key.
|
|
240
|
+
It does not verify that every application route or function is working; validate those with application-specific requests.
|
|
241
|
+
|
|
242
|
+
In JSON output, `endpointHealth.scope` is `management` and `endpointHealth.url` identifies the endpoint checked.
|
|
243
|
+
`endpointHealth.reachable` records whether an HTTP response arrived, while `httpStatus` and `authenticated` distinguish HTTP success from authentication or authorization failures.
|
|
244
|
+
The top-level `authenticated` field indicates that the CLI acquired a token, not that the endpoint accepted it.
|
|
245
|
+
`endpointHealth.errorCode` is `null` on success, or a stable code such as `http`, `redirect`, `timeout`, `connection-refused`, or `network`; `error` and `hint` provide human-readable details.
|
|
246
|
+
Optional key-retrieval problems appear separately in `endpointHealth.metadata.error`, which is `null` on success or `unexpected-format` for an unsupported response body; the saved deployment key is not changed.
|
|
247
|
+
|
|
248
|
+
The command exits with `0` when the management request succeeds, `1` when deployment configuration is missing or another command error occurs, or `2` when the check fails, cannot authenticate, or is cancelled.
|
|
249
|
+
HTTP errors, timeouts, and connection failures return `2`, even when the server is reachable.
|
|
250
|
+
An unexpected metadata format alone does not fail a successful management request.
|
|
251
|
+
|
|
206
252
|
When static content is deployed, the human-readable output includes its public URL:
|
|
207
253
|
|
|
208
254
|
```text
|
|
@@ -236,11 +282,11 @@ Running `npx rayfin up` again updates the same deployment rather than creating a
|
|
|
236
282
|
|
|
237
283
|
For targeted updates, use the subcommands:
|
|
238
284
|
|
|
239
|
-
| Command
|
|
240
|
-
|
|
|
241
|
-
| `npx rayfin up`
|
|
242
|
-
| `npx rayfin up db apply`
|
|
243
|
-
| `npx rayfin up staticapp deploy` | Static content only.
|
|
285
|
+
| Command | What it updates |
|
|
286
|
+
| -------------------------------- | --------------------------------------------------- |
|
|
287
|
+
| `npx rayfin up` | Everything: settings, database, and static content. |
|
|
288
|
+
| `npx rayfin up db apply` | Database schema only. |
|
|
289
|
+
| `npx rayfin up staticapp deploy` | Static content only. |
|
|
244
290
|
|
|
245
291
|
## Troubleshooting
|
|
246
292
|
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
---
|
|
2
|
+
sidebar_position: 4
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Direct Entra token sign-in
|
|
6
|
+
|
|
7
|
+
Use `signInWithEntraToken()` when your application already has a delegated Microsoft Entra access token and wants to call a Rayfin app as that user.
|
|
8
|
+
The helper exchanges it for a Rayfin session on your existing `Auth` instance, so attached SDK clients can make authenticated requests.
|
|
9
|
+
It works in browsers and Node.js without a popup, iframe, handoff code, or redirect.
|
|
10
|
+
|
|
11
|
+
For a portal signing in an embedded app rather than itself, use the [external embed host](./external-embed-host.md).
|
|
12
|
+
For a browser app that needs Fabric to perform interactive sign-in, use the [Fabric broker flow](./fabric.md).
|
|
13
|
+
|
|
14
|
+
## Prerequisites
|
|
15
|
+
|
|
16
|
+
Enable external Entra exchange in the target app's `rayfin/rayfin.yml` and deploy the updated configuration:
|
|
17
|
+
|
|
18
|
+
```yaml
|
|
19
|
+
services:
|
|
20
|
+
auth:
|
|
21
|
+
enabled: true
|
|
22
|
+
fabric:
|
|
23
|
+
enabled: true
|
|
24
|
+
externalEntraExchange: true
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
The direct exchange must also be available in the target Fabric environment.
|
|
28
|
+
Your Entra token must:
|
|
29
|
+
|
|
30
|
+
- Be a delegated user token, not an app-only service principal token.
|
|
31
|
+
- Target the Fabric/Power BI audience accepted by the deployment.
|
|
32
|
+
- Include the delegated `Item.Execute.All` scope.
|
|
33
|
+
- Be issued in the target item's owning Fabric tenant.
|
|
34
|
+
|
|
35
|
+
The user must have Execute permission on that item.
|
|
36
|
+
For production Power BI, request the `https://analysis.windows.net/powerbi/api/Item.Execute.All` scope through your identity library.
|
|
37
|
+
Development environments may use a different resource.
|
|
38
|
+
The SDK does not acquire the Entra token or handle consent.
|
|
39
|
+
|
|
40
|
+
## Install
|
|
41
|
+
|
|
42
|
+
For an app using `RayfinClient`:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
npm install @microsoft/rayfin-client @microsoft/rayfin-auth-provider-fabric
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Sign in an existing client
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
import { RayfinClient } from '@microsoft/rayfin-client';
|
|
52
|
+
import { signInWithEntraToken } from '@microsoft/rayfin-auth-provider-fabric';
|
|
53
|
+
|
|
54
|
+
const client = new RayfinClient({
|
|
55
|
+
baseUrl: rayfinEndpoint,
|
|
56
|
+
publishableKey,
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const session = await signInWithEntraToken(client.auth, {
|
|
60
|
+
entraToken,
|
|
61
|
+
});
|
|
62
|
+
console.log('Authenticated', session.isAuthenticated);
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
`rayfinEndpoint` is your trusted HTTPS AppBackend workload API base URL, including the deployment's capacity/workspace/artifact path.
|
|
66
|
+
Use the same backend base URL as your data client, not the app's static-hosting URL or the full token endpoint.
|
|
67
|
+
The helper preserves that path and appends `/api/auth/v1/brokered/token`; there is no separate endpoint option to keep in sync.
|
|
68
|
+
The base must be absolute HTTPS, including for localhost; relative proxy URLs and URLs containing credentials, query strings, or fragments are not accepted.
|
|
69
|
+
`entraToken` is the raw access token string without the `Bearer` scheme prefix.
|
|
70
|
+
Never accept the endpoint from an untrusted caller.
|
|
71
|
+
|
|
72
|
+
The helper establishes the session on `client.auth`.
|
|
73
|
+
Data and function operations on that client then use the Rayfin access token automatically.
|
|
74
|
+
The returned `OpaqueSession` exposes user and session metadata without exposing tokens.
|
|
75
|
+
Each call explicitly exchanges the supplied token; it does not skip the exchange just because a previous session exists.
|
|
76
|
+
Concurrent direct sign-ins on the same `Auth` instance run in invocation order.
|
|
77
|
+
|
|
78
|
+
## Node.js and standalone SDK clients
|
|
79
|
+
|
|
80
|
+
You can construct `Auth` and `ApiClient` directly without `RayfinClient`:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
npm install @microsoft/rayfin-auth @microsoft/rayfin-lib @microsoft/rayfin-auth-provider-fabric
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
import { Auth } from '@microsoft/rayfin-auth';
|
|
88
|
+
import { ApiClient } from '@microsoft/rayfin-lib';
|
|
89
|
+
import { signInWithEntraToken } from '@microsoft/rayfin-auth-provider-fabric';
|
|
90
|
+
|
|
91
|
+
const apiClient = new ApiClient({
|
|
92
|
+
baseUrl: rayfinEndpoint,
|
|
93
|
+
publishableKey,
|
|
94
|
+
});
|
|
95
|
+
const auth = new Auth(apiClient, { storage: false });
|
|
96
|
+
auth.attachToClient(apiClient);
|
|
97
|
+
|
|
98
|
+
try {
|
|
99
|
+
const session = await signInWithEntraToken(auth, { entraToken });
|
|
100
|
+
console.log('Authenticated', session.isAuthenticated);
|
|
101
|
+
// Use data or other SDK clients configured with apiClient here.
|
|
102
|
+
} finally {
|
|
103
|
+
auth.destroy();
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Neither the import nor this direct sign-in requires `window`, `document`, or `localStorage`.
|
|
108
|
+
`storage: false` keeps the Rayfin session in memory.
|
|
109
|
+
Use separate instances per user in server applications; do not share mutable user sessions across requests from different users.
|
|
110
|
+
Call `auth.destroy()` when the instance is no longer needed to release its timers and listeners.
|
|
111
|
+
`RayfinServerClient` uses an access-token configuration instead of exposing `auth`, so it is not passed directly to this helper.
|
|
112
|
+
|
|
113
|
+
## Session lifetime
|
|
114
|
+
|
|
115
|
+
Persistence follows your `Auth` configuration.
|
|
116
|
+
The SDK does not persist the supplied Entra token in the Rayfin session.
|
|
117
|
+
Subsequent refresh uses the Rayfin refresh token through the ordinary auth flow rather than repeating the external exchange.
|
|
118
|
+
If the session can no longer refresh, obtain another Entra token and explicitly sign in again.
|
|
119
|
+
|
|
120
|
+
## Errors and browser considerations
|
|
121
|
+
|
|
122
|
+
The helper rejects with `AuthError` rather than returning a previous session as a successful sign-in.
|
|
123
|
+
On failure, an existing unexpired session remains in memory; successful sign-in replaces it without revoking the previous server session.
|
|
124
|
+
Do not publish authenticated UI or perform actions for a newly selected account until its sign-in succeeds.
|
|
125
|
+
|
|
126
|
+
| Error code | Meaning |
|
|
127
|
+
| --- | --- |
|
|
128
|
+
| `INVALID_REQUEST` | Invalid local token or endpoint configuration. |
|
|
129
|
+
| `EXCHANGE_NOT_ENABLED` | External Entra exchange is disabled for the project. |
|
|
130
|
+
| `AUTH_FAILED` | The Entra token was rejected; check audience, tenant, scope, and expiry. |
|
|
131
|
+
| `INSUFFICIENT_PERMISSIONS` | The user lacks Execute permission on the item. |
|
|
132
|
+
| `NOT_AVAILABLE` | The endpoint is unavailable in the target environment or the URL is wrong. |
|
|
133
|
+
| `TOKEN_EXCHANGE_FAILED` | A network or other HTTP failure prevented the exchange. |
|
|
134
|
+
| `INVALID_TOKEN_RESPONSE` | The service returned an invalid token response. |
|
|
135
|
+
|
|
136
|
+
The exchange does not follow redirects or automatically retry session issuance.
|
|
137
|
+
Errors do not include the Entra token or raw server response.
|
|
138
|
+
In browsers, the service must allow your origin and authorization header through its CORS policy.
|
|
139
|
+
The direct helper does not require a user gesture, but your identity library may require one when obtaining the Entra token interactively.
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
---
|
|
2
|
+
sidebar_position: 3
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# External embed host
|
|
6
|
+
|
|
7
|
+
The external embed host lets a **third-party portal** embed a Rayfin app in an iframe and sign the user in with the portal's own Microsoft Entra identity.
|
|
8
|
+
Use it when your app is hosted outside the Fabric Portal — a standalone web app, an internal tool, or any page that already holds a delegated Entra token — and you want to broker authentication for an embedded Rayfin app without a popup or redirect.
|
|
9
|
+
|
|
10
|
+
This is the parent-page counterpart to [Fabric brokered auth](./fabric.md).
|
|
11
|
+
Fabric auth signs a Rayfin app in when Fabric hosts it; the external embed host signs it in when *your* page hosts it.
|
|
12
|
+
|
|
13
|
+
The parent page holds a delegated Entra token and answers the embedded app's handoff request.
|
|
14
|
+
The embedded app never sees the token — it receives only a single-use handoff code that it exchanges for a Rayfin session.
|
|
15
|
+
|
|
16
|
+
## When to use it
|
|
17
|
+
|
|
18
|
+
Use `@microsoft/rayfin-embed-host` when **all** of these are true:
|
|
19
|
+
|
|
20
|
+
- Your page embeds a Rayfin app in an iframe.
|
|
21
|
+
- Your page is not the Fabric Portal, so the in-Fabric embed host is unavailable.
|
|
22
|
+
- Your page can obtain a delegated Entra access token for the signed-in user.
|
|
23
|
+
|
|
24
|
+
If your app runs inside the Fabric Portal iframe, use [Fabric brokered auth](./fabric.md) instead — you do not need this package.
|
|
25
|
+
|
|
26
|
+
## How it works
|
|
27
|
+
|
|
28
|
+
1. Your page calls `createEmbedHost()` and then mounts the Rayfin app in an iframe.
|
|
29
|
+
2. The embedded app calls `initEmbeddedAuth()` on startup and posts a one-shot readiness signal to the parent window.
|
|
30
|
+
3. The host checks the iframe's origin against `allowedOrigins` and replies with an acknowledgement, classifying the scenario as an external embed.
|
|
31
|
+
4. The embedded app signs out, then sends a correlated handoff request carrying its brokered-authorize endpoint URL, its Fabric artifact id, the return origin, and a PKCE challenge.
|
|
32
|
+
5. The host validates the return origin against `allowedOrigins`, calls `getAccessToken()` to obtain your delegated Entra token, and posts it to the app's `brokered/authorize/external` endpoint.
|
|
33
|
+
6. The endpoint returns a single-use handoff code, which the host sends back to the iframe in the correlated response.
|
|
34
|
+
7. The embedded app exchanges the handoff code for a Rayfin session — the user is signed in with no popup, redirect, or user click.
|
|
35
|
+
|
|
36
|
+
The readiness signal is sent **once** with no retry.
|
|
37
|
+
Register the host before you mount the iframe so the listener is live when the signal arrives.
|
|
38
|
+
|
|
39
|
+
The external embed scenario is detected from this acknowledgement alone — the embedded Rayfin app needs no special query flag (such as `fabricEmbedded`) to enter external embed mode.
|
|
40
|
+
The embedded app must await `initEmbeddedAuth()` before restoring a stored user or rendering authenticated content.
|
|
41
|
+
Do not skip this call when `auth.getSession()` already reports an authenticated session: that session may belong to a different user than the parent portal's current user.
|
|
42
|
+
|
|
43
|
+
If no host acknowledges the readiness signal, the embedded app falls back to its normal Fabric login waterfall, so a page that never calls `createEmbedHost()` is unaffected.
|
|
44
|
+
|
|
45
|
+
## Install
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
npm install @microsoft/rayfin-embed-host
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Register the host before mounting the iframe
|
|
52
|
+
|
|
53
|
+
Call `createEmbedHost()` before the Rayfin iframe loads.
|
|
54
|
+
The embedded app emits its readiness signal once, immediately on startup, and there is no retry — if the listener is not yet registered, the handshake is missed and the app falls back to its normal login flow.
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
import { createEmbedHost } from '@microsoft/rayfin-embed-host';
|
|
58
|
+
|
|
59
|
+
// Register BEFORE mounting the Rayfin iframe.
|
|
60
|
+
const host = createEmbedHost({
|
|
61
|
+
allowedOrigins: ['https://my-rayfin-app.example.com'],
|
|
62
|
+
getAccessToken: () => acquireDelegatedEntraToken(),
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
// Now mount the iframe pointing at the embedded Rayfin app.
|
|
66
|
+
const iframe = document.createElement('iframe');
|
|
67
|
+
iframe.src = 'https://my-rayfin-app.example.com';
|
|
68
|
+
document.querySelector('#app-embed')?.append(iframe);
|
|
69
|
+
|
|
70
|
+
// When the embed is torn down:
|
|
71
|
+
host.dispose();
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Options
|
|
75
|
+
|
|
76
|
+
`createEmbedHost()` takes an `EmbedHostOptions` object.
|
|
77
|
+
|
|
78
|
+
| Property | Type | Description |
|
|
79
|
+
| --- | --- | --- |
|
|
80
|
+
| `allowedOrigins` | `string[]` | Origins of the embedded Rayfin app(s) this host brokers for. Set it to your app's URL origin(s), for example `https://my-rayfin-app.example.com`. The same list gates both the iframe that sends the handshake and the return origin the handoff code is bound to. |
|
|
81
|
+
| `getAccessToken` | `() => string \| Promise<string>` | Yields your page's delegated Entra access token. Invoked once per handoff request; the returned token is attached only to the outbound authorization call and is never cached across requests. |
|
|
82
|
+
|
|
83
|
+
## Providing the access token
|
|
84
|
+
|
|
85
|
+
`getAccessToken` is your integration point with your page's identity stack.
|
|
86
|
+
Return the delegated Entra access token for the currently signed-in user — for example, from MSAL's `acquireTokenSilent`, a server-side session endpoint, or whatever token cache your portal already uses.
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
const host = createEmbedHost({
|
|
90
|
+
allowedOrigins: ['https://my-rayfin-app.example.com'],
|
|
91
|
+
getAccessToken: async () => {
|
|
92
|
+
const result = await msalInstance.acquireTokenSilent({
|
|
93
|
+
scopes: ['<your-api-scope>'],
|
|
94
|
+
account: msalInstance.getActiveAccount()!,
|
|
95
|
+
});
|
|
96
|
+
return result.accessToken;
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
The host calls `getAccessToken()` fresh for every handoff request, so returning a short-lived token is fine — you do not need to cache one yourself.
|
|
102
|
+
|
|
103
|
+
## Cleanup
|
|
104
|
+
|
|
105
|
+
`createEmbedHost()` registers a `message` listener on the parent window.
|
|
106
|
+
Call `dispose()` when you remove the iframe (for example, on route change or component unmount) to remove the listener and stop brokering handoffs.
|
|
107
|
+
`dispose()` is idempotent.
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
host.dispose();
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Security
|
|
114
|
+
|
|
115
|
+
- **Single origin allowlist** — `allowedOrigins` gates both the browser-attested `event.origin` of the iframe that posts the handshake and handoff request, and the `returnOrigin` the handoff code is bound to.
|
|
116
|
+
Messages from any other origin are ignored, and a request naming a return origin outside the list is rejected before any network call.
|
|
117
|
+
- **Token never leaves the parent** — The delegated Entra token is attached only to the outbound `brokered/authorize/external` call.
|
|
118
|
+
It is never sent over the `postMessage` bridge and never returned to the iframe.
|
|
119
|
+
- **PKCE S256** — The embedded app generates the PKCE challenge; the handoff code is bound to it and is single-use.
|
|
120
|
+
- **Correlated responses** — Each handoff response is matched to its request by a correlation id, so a response is only delivered to the request that asked for it.
|
|
121
|
+
|
|
122
|
+
## Troubleshooting
|
|
123
|
+
|
|
124
|
+
- **The app keeps its stored session without signing out or calling the external endpoint** — Check the embedded app's startup ordering.
|
|
125
|
+
Call and await `initEmbeddedAuth()` before checking for a stored user; importing the provider package alone does not start authentication.
|
|
126
|
+
- **The app falls back to a popup or normal Fabric login** — The readiness signal was missed.
|
|
127
|
+
Confirm `createEmbedHost()` runs before the iframe is mounted, and that the iframe's origin is listed in `allowedOrigins`.
|
|
128
|
+
- **Handoff request rejected before any network call** — The request's return origin is not in `allowedOrigins`.
|
|
129
|
+
Add the embedded app's exact origin (scheme, host, and port) to the list.
|
|
130
|
+
- **Authorization call fails** — Verify `getAccessToken()` returns a valid delegated Entra token with the scope your app's `brokered/authorize/external` endpoint expects.
|
|
131
|
+
- **Nothing happens after mounting the iframe** — Confirm the embedded Rayfin app is built with an external-Entra-enabled auth provider (see [Fabric brokered auth](./fabric.md) for the iframe side).
|
|
@@ -7,12 +7,18 @@ sidebar_position: 2
|
|
|
7
7
|
Fabric authentication lets users sign in to your Rayfin application with their existing Microsoft Entra identity through the Fabric Portal.
|
|
8
8
|
No separate login form is needed — users authenticate once in Fabric and your app inherits that session automatically.
|
|
9
9
|
|
|
10
|
-
The SDK supports
|
|
10
|
+
The SDK supports three modes:
|
|
11
11
|
|
|
12
12
|
- **Popup flow** — your app opens the Fabric Portal in a new browser tab, the user authenticates, and the tab closes automatically.
|
|
13
13
|
- **Embedded flow** — your app runs inside a Fabric iframe and inherits the session via `postMessage` with no popup, redirect, or user interaction.
|
|
14
|
+
- **Direct token flow** — your browser or Node.js app supplies an existing delegated Entra token and establishes a Rayfin session without a browser broker.
|
|
15
|
+
See [Direct Entra token sign-in](./direct-entra-auth.md).
|
|
14
16
|
|
|
15
|
-
|
|
17
|
+
The popup and embedded flows use PKCE S256, `postMessage` origin validation, and state nonces.
|
|
18
|
+
The direct flow uses an HTTPS token exchange with delegated-token validation and item-level Execute permission checks.
|
|
19
|
+
|
|
20
|
+
> **Embedding outside Fabric?** If your app runs inside an iframe on your own third-party portal rather than the Fabric Portal, the portal brokers sign-in with its own Entra token via the parent-page [external embed host](./external-embed-host.md).
|
|
21
|
+
> On startup the embedded app posts a one-shot readiness signal and briefly waits for the parent to acknowledge it; if no external embed host answers, the app falls back to the standard Fabric login waterfall described below with no added user-visible delay.
|
|
16
22
|
|
|
17
23
|
## How it works
|
|
18
24
|
|
|
@@ -103,7 +109,9 @@ async function handleSignIn() {
|
|
|
103
109
|
### Embedded flow: automatic authentication on startup
|
|
104
110
|
|
|
105
111
|
Call `initEmbeddedAuth()` once at app startup (for example, in a React `useEffect` or initialization routine).
|
|
106
|
-
|
|
112
|
+
Await it before restoring a stored user or rendering authenticated content, even when a persisted session exists.
|
|
113
|
+
It is safe to call on every page load: standalone pages return `null` immediately, while framed pages briefly wait for an external embed acknowledgement before choosing the login path.
|
|
114
|
+
Keep session-change observers from publishing a stored user while initialization is pending.
|
|
107
115
|
|
|
108
116
|
```typescript
|
|
109
117
|
import { RayfinClient } from '@microsoft/rayfin-client';
|
|
@@ -130,7 +138,7 @@ if (session) {
|
|
|
130
138
|
|
|
131
139
|
Import `@microsoft/rayfin-auth-provider-fabric` statically in your app entry module rather than only via dynamic `import()`.
|
|
132
140
|
The package captures the `?fabricEmbedded=true` URL flag into `sessionStorage` as a side effect at module load, and that must happen on the initial page load before any client-side navigation strips the query string (for example, a post-logout redirect to `/login`).
|
|
133
|
-
|
|
141
|
+
Do not condition the startup call on the absence of a stored session; that bypasses the SDK's identity check and external embed handshake.
|
|
134
142
|
|
|
135
143
|
### Detecting embedded mode
|
|
136
144
|
|
|
@@ -262,7 +270,7 @@ Most apps should use `ensureSignedInWithFabric` instead.
|
|
|
262
270
|
|
|
263
271
|
## Security
|
|
264
272
|
|
|
265
|
-
- **PKCE S256** —
|
|
273
|
+
- **PKCE S256** — The popup and embedded flows generate a cryptographic code verifier and challenge to prevent authorization code interception.
|
|
266
274
|
- **State nonce** — A random nonce ties the postMessage response to the originating flow, preventing CSRF.
|
|
267
275
|
- **In-closure code verifier** — The PKCE `code_verifier` is held in memory (closure) and never persisted to localStorage.
|
|
268
276
|
- **Origin validation** — The SDK validates `event.origin` on incoming messages against `fabricPortalUrl`.
|
|
@@ -26,8 +26,14 @@ Rayfin supports multiple authentication methods that you can enable independentl
|
|
|
26
26
|
- **Magic link** — Passwordless sign-in via email links.
|
|
27
27
|
- **Fabric brokered auth** — Single sign-on through the Microsoft Fabric Portal using the user's Entra identity.
|
|
28
28
|
See [Fabric Brokered Auth](./fabric.md) for setup and usage.
|
|
29
|
+
- **Direct Entra token sign-in** — Exchange an existing delegated Entra token for a Rayfin session from a browser or Node.js app.
|
|
30
|
+
See [Direct Entra token sign-in](./direct-entra-auth.md).
|
|
31
|
+
- **External embed host** — Broker sign-in for a Rayfin app embedded in your own third-party portal, using the portal's Entra token.
|
|
32
|
+
See [External embed host](./external-embed-host.md).
|
|
29
33
|
|
|
30
34
|
## Next steps
|
|
31
35
|
|
|
32
36
|
- [How to configure auth](./overview.md)
|
|
33
37
|
- [Fabric brokered auth](./fabric.md)
|
|
38
|
+
- [Direct Entra token sign-in](./direct-entra-auth.md)
|
|
39
|
+
- [External embed host](./external-embed-host.md)
|
|
@@ -8,6 +8,10 @@ Connectors let a Rayfin app read from — and, for some types, write to — Micr
|
|
|
8
8
|
|
|
9
9
|
The `connector` command group is always available.
|
|
10
10
|
|
|
11
|
+
**Lakehouse scope:** `fabric-sqlanalytics` connects only to a Lakehouse's SQL analytics endpoint.
|
|
12
|
+
It can read SQL-visible tables and views, but it cannot directly open files from the Lakehouse `Files` area, such as PDFs or images.
|
|
13
|
+
This connector is read-only; the Warehouse and SQL Database connectors also support write operations.
|
|
14
|
+
|
|
11
15
|
> **`kusto` authoring is held in this release.** `connector types` and `connector search` omit it, and `connector add --type kusto` refuses it. A project that **already declares** a Kusto connector is unaffected: it still validates, deploys through `rayfin up`, and answers `connector invoke`. Kusto material in these docs describes that preserved runtime contract and the authoring path for when it ships.
|
|
12
16
|
|
|
13
17
|
Each command has its own reference page:
|
|
@@ -54,6 +54,34 @@ What `output` holds depends on the connector. `fabric-semanticmodel` normalises
|
|
|
54
54
|
|
|
55
55
|
A resolved call is **not** automatically a success, and the failure signal depends on the same distinction. A connector that normalises reports Power BI failures — expired token, missing Build permission, throttling — as `{status: 'error', error, requestId}`, where `error` carries `category`, `message`, and optional `code` and `details`. A connector that returns the raw envelope reports failure as `status: 'Failed'` instead. The CLI reads both, converts either into a non-zero exit, and surfaces the service-supplied request id for tracing.
|
|
56
56
|
|
|
57
|
+
In JSON mode, failures keep the top-level `error` as a human-readable **string**, with `recovery` and `requestId` when available.
|
|
58
|
+
Connector failures additionally expose a `connectorError` object containing the available `message`, `category`, `code`, and `details` fields.
|
|
59
|
+
Scalar values are stringified and structured values are JSON-encoded, so a numeric `code` or object `details` survives; empty and unavailable fields are omitted, and unrelated CLI failures do not acquire connector metadata.
|
|
60
|
+
The remediation hint stays on the top-level `recovery` string only, so `connectorError` never carries a CLI-fabricated hint.
|
|
61
|
+
This applies to both direct and deployed invocation, including DAX errors returned inside an HTTP 200 Arrow stream.
|
|
62
|
+
The semantic-model SDK also preserves the Arrow error code and description as `error.code` and `error.details` in its normalized result.
|
|
63
|
+
Existing engine-markup cleanup still applies to normalized messages and details.
|
|
64
|
+
|
|
65
|
+
For example, an invalid DAX query exits with code `1` and can emit:
|
|
66
|
+
|
|
67
|
+
```json
|
|
68
|
+
{
|
|
69
|
+
"status": "error",
|
|
70
|
+
"error": "Connector invoke failed (DAX_ERROR): Column not found",
|
|
71
|
+
"recovery": "The service ran the operation and reported an error. Fix the query and retry.",
|
|
72
|
+
"requestId": "service-request-id",
|
|
73
|
+
"connectorError": {
|
|
74
|
+
"message": "Column not found",
|
|
75
|
+
"category": "query",
|
|
76
|
+
"code": "DAX_ERROR",
|
|
77
|
+
"details": "The column Foo does not exist"
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Read `connectorError.code` and `connectorError.details` rather than parsing the display string.
|
|
83
|
+
Service diagnostics may contain query or model content; review them before sharing or recording them in logs.
|
|
84
|
+
|
|
57
85
|
## Examples
|
|
58
86
|
|
|
59
87
|
```bash
|
package/assets/docs/cli/index.md
CHANGED
|
@@ -126,3 +126,25 @@ To disable telemetry, set the following environment variable:
|
|
|
126
126
|
```bash
|
|
127
127
|
export RAYFIN_TELEMETRY_OPTOUT=1
|
|
128
128
|
```
|
|
129
|
+
|
|
130
|
+
## Diagnostic logs
|
|
131
|
+
|
|
132
|
+
`npx rayfin up` and workflow-based `npx rayfin dev` record detailed diagnostics under `~/.rayfin/logs/` even when `--verbose` is absent, including when using `--json` or `--output json`.
|
|
133
|
+
After a failure, open the file identified by `Diagnostic log:` to inspect the original invocation without rerunning it.
|
|
134
|
+
JSON failures include the same path in the `diagnosticLog` field of the single result object.
|
|
135
|
+
`dev` JSON failures also include a `hint` with recovery guidance, including provider/configuration preflight errors and unexpected failures.
|
|
136
|
+
|
|
137
|
+
Adding `--verbose` also mirrors diagnostic records to stderr while `up` or `dev` runs.
|
|
138
|
+
The CLI rejects combining `--verbose` with `--json` or `--output json`; detailed diagnostics are still recorded in the log file without `--verbose`.
|
|
139
|
+
This capability applies to workflow-based `up` and `dev` sessions, not standalone subcommands or Docker maintenance flags such as `dev --stop`.
|
|
140
|
+
|
|
141
|
+
`dev` preserves normal frontend and Functions terminal output and flushes its log after cleanup on Ctrl-C, runtime failure, or normal completion.
|
|
142
|
+
Piped runtime and build output is captured with a 1 MiB limit per stream.
|
|
143
|
+
Interactive runtimes that inherit the terminal keep their keyboard and TTY behavior; their console output is not captured, and the log records that limitation alongside lifecycle events.
|
|
144
|
+
|
|
145
|
+
Logs stay on your machine and are independent of telemetry opt-out.
|
|
146
|
+
The log directory is shared across projects on your machine, so the retention limits below apply across all projects using it.
|
|
147
|
+
Known credential patterns are redacted, and build output is bounded, but review logs before sharing them because project tools can emit their own content.
|
|
148
|
+
Retention is best-effort: logs older than 14 days are pruned, with targets of 20 invocation files and 100 MiB total; each file is limited to 10 MiB.
|
|
149
|
+
If `RAYFIN_CONFIG_DIR` is set, logs use its `logs/` subdirectory instead.
|
|
150
|
+
An unavailable or full log directory does not change the command result.
|
|
@@ -20,11 +20,10 @@ Every `npm create @microsoft/rayfin@latest` or `npx rayfin init` invocation can
|
|
|
20
20
|
External and local template sources are discovered through `rayfin-template.yml` manifests inside the selected source directory.
|
|
21
21
|
Built-in templates are packaged with the CLI and appear in `--list-templates` automatically.
|
|
22
22
|
|
|
23
|
-
> **Universal App is
|
|
24
|
-
>
|
|
25
|
-
> but
|
|
26
|
-
>
|
|
27
|
-
> template directly.
|
|
23
|
+
> **Universal App is available as the built-in `blankapp` template.**
|
|
24
|
+
> The visible `blankapp` entry appears in `--list-templates` and is available in the CLI and VS Code.
|
|
25
|
+
> Its canonical `universal-app` name remains hidden to avoid a duplicate listing, but plugin automation can still select it explicitly with `--template universal-app`.
|
|
26
|
+
> Both names scaffold the same committed workspace template.
|
|
28
27
|
> This does not change support for ordinary local directories, git repositories, or registered templates.
|
|
29
28
|
|
|
30
29
|
## List available templates
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@microsoft/rayfin-guide",
|
|
3
|
-
"version": "1.36.0-alpha.
|
|
3
|
+
"version": "1.36.0-alpha.1675",
|
|
4
4
|
"description": "Cross-cutting Builder guides for the Rayfin platform — discovered by `@microsoft/rayfin-docs` via the `rayfinDocs` package.json field convention.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|