Rayfin

@microsoft/rayfin-auth-provider-fabric

Fabric auth provider reference for Fabric SSO, direct Entra token exchange, embedded handoff, and external embed support.

@microsoft/rayfin-auth-provider-fabric signs Rayfin users in with Microsoft Entra ID. Browser helpers broker through Fabric SSO. signInWithEntraToken() exchanges an existing delegated Entra token directly in browsers or Node.js. New in 1.36

The package operates on an Auth instance from @microsoft/rayfin-auth.

Note

This package's catalog listing can mention MSAL, but the installed implementation does not depend on MSAL.js. Browser broker flows implement PKCE S256 and postMessage against Fabric. Direct token sign-in expects your code to obtain the delegated Entra token.

Installation

npm install @microsoft/rayfin-auth-provider-fabric @microsoft/rayfin-auth @microsoft/rayfin-lib

Where each flow works

FlowRuntimeUse when
ensureSignedInWithFabric popup flowBrowserThe app needs Fabric to perform interactive sign-in from a standalone origin such as http://localhost:5173 or the deployed site.
initEmbeddedAuth Fabric iframe flowBrowser iframeThe app is loaded inside the Fabric portal and should sign in without a popup.
initEmbeddedAuth external embed flowBrowser iframeA third-party parent page acknowledges the external-embed handshake and brokers auth for the iframe. New in 1.36
signInWithEntraTokenBrowser or Node.jsYour code already has a delegated Entra token and wants to exchange it for a Rayfin session. New in 1.36
signInWithBrokeredTokenBrowser or Node.jsA trusted caller already obtained a Rayfin token response from the brokered exchange endpoint. New in 1.36

Popup and embedded Fabric SSO require a Rayfin backend deployed to Fabric. The popup flow works from any origin listed in allowedRedirectUris. The embedded Fabric flow requires the app to be loaded inside a Fabric iframe.

Exports

export type { FabricAuthOptions };
export type { EntraTokenSignInOptions };
export { bridgeFabricCallback };
export { embeddedFabricLogin };
export { ensureSignedInWithFabric };
export { initEmbeddedAuth };
export { initiateFabricLogin };
export { requestHandoff };
export { signInWithBrokeredToken, signInWithEntraToken };

The public root can be imported in Node.js. Browser broker helpers still require browser APIs such as window.open(), postMessage, BroadcastChannel, and window.location.

FabricAuthOptions

interface FabricAuthOptions {
  workspaceId: string;
  projectId: string;
  fabricPortalUrl: string;
  returnOrigin: string;
  callbackUrl?: string;
  fabricEmbedded?: boolean;
}
OptionTypeDescription
workspaceIdstringFabric workspace ID.
projectIdstringFabric project or AppBackend artifact ID.
fabricPortalUrlstringFabric portal URL. Existing path and query parameters are preserved when the broker URL is built.
returnOriginstringBare origin of the app that initiated auth, such as window.location.origin.
callbackUrlstringLegacy redirect callback URL. Defaults to ${returnOrigin}/auth/callback. Deprecated for postMessage-capable portals.
fabricEmbeddedbooleanForces embedded mode. The SDK also detects ?fabricEmbedded=true and a stored embedded flag.

ensureSignedInWithFabric

function ensureSignedInWithFabric(
  auth: Auth,
  options: FabricAuthOptions
): Promise<OpaqueSession>;

Browser-only primary entry point for Fabric SSO. It runs a waterfall where the first successful step short-circuits the rest:

  1. Return a safe existing session.
  2. Try auth.refreshSession() if a refresh token exists.
  3. Use embedded postMessage handoff if Fabric embedded mode or external-embed classification applies. Changed in 1.36
  4. Open the Fabric broker popup.

Step 4 calls window.open(). Call this function directly from a user gesture.

src/auth/signIn.ts
import { RayfinClient } from '@microsoft/rayfin-client';
import { ensureSignedInWithFabric } from '@microsoft/rayfin-auth-provider-fabric';

const client = new RayfinClient({
  baseUrl: import.meta.env.VITE_RAYFIN_API_URL,
  publishableKey: import.meta.env.VITE_RAYFIN_PUBLISHABLE_KEY,
});

document.querySelector('#sign-in')?.addEventListener('click', async () => {
  const session = await ensureSignedInWithFabric(client.auth, {
    workspaceId: import.meta.env.VITE_FABRIC_WORKSPACE_ID,
    projectId: import.meta.env.VITE_FABRIC_ITEM_ID,
    fabricPortalUrl: import.meta.env.VITE_FABRIC_PORTAL_URL,
    returnOrigin: window.location.origin,
  });

  console.log('Signed in:', session.user?.email);
});

initEmbeddedAuth

function initEmbeddedAuth(
  auth: Auth,
  options: FabricAuthOptions
): Promise<OpaqueSession | null>;

Browser-only startup helper. It never opens a popup. It first runs the one-shot external-embed classification handshake, then proceeds when either a third-party parent acknowledges that scenario or Fabric embedded mode is detected. Changed in 1.36

It returns null when no embedded scenario applies. Await it before trusting a stored session in iframe scenarios.

src/auth/bootstrap.ts
import { initEmbeddedAuth } from '@microsoft/rayfin-auth-provider-fabric';

const session = await initEmbeddedAuth(client.auth, fabricOptions);
if (session) {
  console.log('Embedded session established:', session.user?.email);
}

Warning

Import @microsoft/rayfin-auth-provider-fabric with a static import, not only a dynamic import(). The package captures the ?fabricEmbedded=true URL flag into sessionStorage during module load.

initiateFabricLogin

function initiateFabricLogin(auth: Auth, options: FabricAuthOptions): Promise<void>;

Low-level popup helper used by ensureSignedInWithFabric(). It opens the broker, sends the PKCE challenge after brokeredAuth.ready, receives brokeredAuth.handoff, exchanges the handoff code, and installs the session. Most apps should use ensureSignedInWithFabric() instead.

signInWithEntraToken

interface EntraTokenSignInOptions {
  entraToken: string;
}

function signInWithEntraToken(
  auth: Auth,
  options: EntraTokenSignInOptions
): Promise<OpaqueSession>;

Exchanges an existing delegated Entra token for a Rayfin session. It works in browsers and Node.js and does not require FabricAuthOptions, a popup, or an iframe. New in 1.36

The Auth instance's ApiClient must point at an absolute HTTPS AppBackend workload API base URL. The helper resolves /api/auth/v1/brokered/token against that base and rejects URLs with credentials, query strings, fragments, whitespace, backslashes, or non-HTTPS protocols.

scripts/directSignIn.ts
import { Auth } from '@microsoft/rayfin-auth';
import { ApiClient } from '@microsoft/rayfin-lib';
import { signInWithEntraToken } from '@microsoft/rayfin-auth-provider-fabric';

const apiClient = new ApiClient({
  baseUrl: process.env.RAYFIN_API_URL!,
  publishableKey: process.env.RAYFIN_PUBLISHABLE_KEY!,
});

const auth = new Auth(apiClient, { storage: false });
auth.attachToClient(apiClient);

try {
  const session = await signInWithEntraToken(auth, {
    entraToken: process.env.ENTRA_ACCESS_TOKEN!,
  });
  console.log('Authenticated:', session.isAuthenticated);
} finally {
  auth.destroy();
}

signInWithBrokeredToken

function signInWithBrokeredToken(
  auth: Auth,
  tokenResponse: TokenResponse
): Promise<OpaqueSession>;

Installs a token response that was already obtained from POST /api/auth/v1/brokered/token by a trusted caller. It performs no network request. Prefer signInWithEntraToken() when the caller has the raw Entra token and an HTTPS-reachable backend. New in 1.36

The local development adapter uses this helper to install a token response obtained through the developer's rayfin login session.

Embedded transport helpers

function embeddedFabricLogin(auth: Auth, options: FabricAuthOptions): Promise<void>;

function requestHandoff(params: {
  callbackUrl: string;
  codeChallenge: string;
  codeChallengeMethod: string;
  state: string;
  timeoutMs?: number;
  brokeredAuthorizeUrl?: string;
  artifactId?: string;
  targetOrigin?: string;
}): Promise<{ handoffCode: string; state: string }>;

These are low-level browser helpers. In external embed mode, embeddedFabricLogin() adds brokeredAuthorizeUrl, artifactId, and a pinned targetOrigin to the handoff request. Normal Fabric embedded payloads remain unchanged. Changed in 1.36

Most applications should call initEmbeddedAuth() rather than these helpers directly.

bridgeFabricCallback

function bridgeFabricCallback(): boolean;

Legacy callback bridge for Fabric portals that redirect the popup to an app callback page. It forwards any Fabric handoff parameters found in the URL back to the opener window and closes the popup. Modern Fabric broker handoff uses postMessage.

Environment variables

rayfin dev and rayfin up write the Fabric coordinates needed for FabricAuthOptions. For Vite apps, framework environment generation maps them to these names:

Source variable (rayfin/.env)Vite variable (.env.local)Maps to
RAYFIN_PUBLIC_ITEM_IDVITE_FABRIC_ITEM_IDprojectId
RAYFIN_PUBLIC_WORKSPACE_IDVITE_FABRIC_WORKSPACE_IDworkspaceId
RAYFIN_PUBLIC_PORTAL_URLVITE_FABRIC_PORTAL_URLfabricPortalUrl

See Fabric SSO and rayfin.yml auth configuration.

Direct token exchange errors

signInWithEntraToken() throws AuthError with these stable codes:

CodeMessage
INVALID_REQUESTA raw Entra access token is required.
INVALID_REQUESTAn absolute HTTPS backend URL is required.
EXCHANGE_NOT_ENABLEDExternal Entra exchange is not enabled.
AUTH_FAILEDEntra authentication failed.
INSUFFICIENT_PERMISSIONSItem Execute permission is required.
NOT_AVAILABLEExternal Entra exchange is not available.
TOKEN_EXCHANGE_FAILEDEntra token exchange failed.
INVALID_TOKEN_RESPONSEThe token exchange returned an invalid token response.

Browser broker errors

CodeMeaning
MISSING_WORKSPACE_IDworkspaceId is missing.
MISSING_PROJECT_IDprojectId is missing.
MISSING_RETURN_ORIGINreturnOrigin is missing.
MISSING_FABRIC_PORTAL_URLfabricPortalUrl is missing.
TAB_BLOCKEDThe broker popup could not open.
PKCE_CHALLENGE_FAILEDPKCE challenge generation failed.
CHALLENGE_DELIVERY_FAILEDThe SDK could not post the PKCE challenge to the broker frame.
FABRIC_AUTH_TIMEOUTThe popup handoff timed out after five minutes.
NO_PARENT_WINDOWEmbedded auth was requested outside an iframe.
STATE_MISMATCHThe embedded handoff response state did not match.
SESSION_NOT_ESTABLISHEDHandoff completed but no authenticated session was installed.

Troubleshooting

SymptomLikely causeFix
Popup blockedCalled outside a synchronous user-gesture handler.Call ensureSignedInWithFabric() directly from a button onClick.
Session not persistingRayfinClient is configured for the wrong backend.Confirm baseUrl and publishableKey are correct.
Handoff times outThe popup handoff code was never received.Confirm returnOrigin matches the app's actual origin and is allowed by the backend.
initEmbeddedAuth() returns nullNo Fabric iframe or external embed host was detected.Use popup sign-in for standalone pages; for iframes, verify the host path.
State mismatchReplayed or stale response.Retry the flow from scratch and investigate repeated failures.
Direct token exchange reports EXCHANGE_NOT_ENABLEDThe target app has not enabled external Entra exchange.Set services.auth.fabric.externalEntraExchange: true and apply runtime settings.

See Errors and troubleshooting for the full site-wide index.

Security notes

  • Popup and embedded Fabric SSO use PKCE S256 and state nonces.
  • The PKCE verifier stays in memory and is not persisted to localStorage.
  • Popup origin checks are advisory because the Fabric extension frame can differ from the portal origin; state plus PKCE are the enforcement boundary.
  • Normal Fabric embedded handoff does not set fabricPortalUrl as targetOrigin; external embed handoff uses the parent origin pinned by classification. Changed in 1.36
  • Direct token exchange never stores the supplied Entra token and sanitizes exchange errors.

Runtime requirements

The package root and signInWithEntraToken() can run in Node.js without browser globals. Use memory-only or custom storage outside a browser.

The popup, iframe, and legacy callback helpers are browser-only. They depend on browser APIs such as window.open(), postMessage, BroadcastChannel, and window.location.

Something wrong on this page?Report an issueEdit this page

On this page