Fabric アプリ用に Fabric SSO 認証を構成する

ユーザーが Fabric ポータルを通じて Microsoft Entra ID でサインインできるように、Fabric アプリ用のシングル サインオン (SSO) を設定します。 この記事では、ハンドオフ フローについて説明し、デプロイされたアプリに必要な構成と SDK 統合を有効にする方法について説明します。

前提条件

Fabric SSO のしくみ

Fabric のシングル サインオン (SSO) は、アプリケーションと Fabric ポータルの間で安全な postMessage ベースのハンドオフを利用します。 リダイレクト ページまたはコールバック ページはありません。

  1. アプリがポップアップでFabric ポータルを開き、postMessage リスナーを登録します。
  2. ユーザーは、Fabric ポータル内のMicrosoft Entra IDを使用して認証を行います。
  3. Fabric拡張機能は、window.opener.postMessage() を介してハンドオフ コードをアプリに送り返します。
  4. SDK は、Rayfin セッション トークンのハンドオフ コードを交換し、セッションを作成します。
  5. Fabric ポップアップは自動的に閉じます。

フローは PKCE (Proof Key for Code Exchange)、state nonces、および postMessage origin validation を使用してセキュリティで保護され、承認コードのインターセプトとクロスサイト要求フォージェリを防ぎます。

Fabric認証を有効にする

Fabric認証構成を rayfin/rayfin.yml ファイルに追加します。

services:
  auth:
    enabled: true
    allowedRedirectUris:
      - http://localhost:5173
    fabric:
      enabled: true

デプロイされたアプリケーションの場合は、再デプロイして更新された設定をプッシュします。

npx rayfin up

デプロイされたアプリの場合、 npx rayfin up は、デプロイされたアプリコールバック URL を allowedRedirectUrisに追加します。

Fabric認証プロバイダーをインストールする (省略可能)

npm create @microsoft/rayfin@latestでスキャフォールディングされたプロジェクトには、既に@microsoft/rayfin-auth-provider-fabricが含まれています。 パッケージがまだないプロジェクトにFabric認証を追加する場合にのみ、手動でインストールします。

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

アプリにサインインとサインアップを追加する

Fabric SSO では、サインインとサインアップの両方に 1 つの API (ensureSignedInWithFabric()) が使用されます。 ユーザーが初めてサインインすると、Fabricは、Microsoft Entra ID ID に基づいて自動的に Rayfin セッションをプロビジョニングします。個別のサインアップ呼び出しはありません。 同じコードパスで、再訪ユーザーにも対応します。

このコードは手動で追加することも、VS Code でGitHub Copilotを使用して生成することもできます。

サインインを手動で追加する

ユーザー ジェスチャ ハンドラー (ボタン選択など) から ensureSignedInWithFabric() を呼び出します。

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,
});

const fabricOptions = {
  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,
};

async function handleSignIn() {
  // Signs in existing users and provisions new users on first sign-in.
  const session = await ensureSignedInWithFabric(client.auth, fabricOptions);
  if (session.isAuthenticated && session.user) {
    console.log('Signed in as:', session.user.email);
  }
}

ポップアップ ブロックを回避するには、同期ユーザー ジェスチャ ハンドラーから関数を呼び出す必要があります。 ユーザー操作によってブラウザーポップアップ保護がトリガーされる前に、ページ読み込み時または非同期チェーン内で呼び出します。

returnOrigin は、ベア オリジン (スキームとホスト、パスなし) である必要があります (たとえば、 https://app.contoso.com)。 SDK はこれを使用して、受信 postMessage イベントを検証します。

サインアウトを手動で追加する

client.auth.signOut()を呼び出してセッションを終了し、キャッシュされたトークンをクリアします。

async function handleSignOut() {
  await client.auth.signOut();
  console.log('Signed out');
}

セッションの変更をサブスクライブして、サインインまたはサインアウトが完了したときに UI を更新します。

client.auth.onSessionChange((session) => {
  console.log('Session changed:', session?.isAuthenticated ? 'signed in' : 'signed out');
});

GitHub Copilotでサインインとサインアップを生成する

VS Code で GitHub Copilot を使用する場合は、Fabric Apps プロジェクトでCopilot Chatを開き、次のようなプロンプトを使用して認証コードをスキャフォールディングします。 Copilotは、Fabric VS Code 拡張機能にバンドルされている Rayfin スキルのパターンに従います。

ゴール Copilot プロンプトの例
サインイン ボタンを追加する Add a Sign in with Fabric button to my React app using ensureSignedInWithFabric from @microsoft/rayfin-auth-provider-fabric. Read workspaceId, projectId, and fabricPortalUrl from VITE_* env vars and set returnOrigin to window.location.origin.
サインアウト ボタンを追加する Add a Sign out button that calls client.auth.signOut() and updates the UI when the session ends.
認証対応 React フックを追加する Create a useFabricAuth React hook that exposes session, signIn, signOut, and isAuthenticated, using ensureSignedInWithFabric and client.auth.onSessionChange.
埋め込みモードのサポート Update my app's entry point to call initEmbeddedAuth on page load so users signed in through the Fabric portal don't have to click Sign in again.
ルートをゲートする Wrap the /dashboard route so it calls ensureSignedInWithFabric before rendering and redirects unauthenticated users to a sign-in page.

Copilotでコードが生成されたら、編集内容を確認し、次のことを確認します。

  • ensureSignedInWithFabric()呼び出しは、ページの読み込み時ではなく、ユーザー ジェスチャ ハンドラー (onClick など) 内で実行されます。
  • returnOriginはベアオリジンであり、allowedRedirectUrisrayfin/rayfin.ymlのいずれかのエントリと一致します。
  • インポートは、(非推奨のコールバック ヘルパーではなく) @microsoft/rayfin-auth-provider-fabric から取得されます。

Fabric iframe 内で埋め込みモードを使用する

アプリがFabric iframe 内で読み込まれる場合 (たとえば、ユーザーがFabric ポータルから開いたときなど)、ポップアップ フローの代わりに埋め込みモードを使用します。

  • 埋め込みモードは、親フレームへの postMessage を介してセッションを取得します。
  • ポップアップは開かないため、ユーザー ジェスチャは必要ないため、ページの読み込み時に呼び出しても安全です。
  • SDK は、URL 内の ?fabricEmbedded=true から埋め込みモードを自動検出します。 オプションで fabricEmbedded: true を設定して強制することもできます。

アプリの起動の早い段階で initEmbeddedAuth() を呼び出します。

import { initEmbeddedAuth } from '@microsoft/rayfin-auth-provider-fabric';
import { client } from './lib/rayfin';

const session = await initEmbeddedAuth(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,
});

if (session) {
  console.log('Signed in via embedded mode:', session.user?.email);
}

initEmbeddedAuth() は、アプリが埋め込みモードで実行されていないときに null を返すので、無条件で呼び出しても安全です。 ensureSignedInWithFabric() また、ポップアップ フローにフォールバックする前に、埋め込みモードが自動的に試行されます。

React でFabric認証を使用する

サインイン、サインアップ、サインアウトを統合するカスタム フックを作成します。

import { useState, useEffect, useCallback } from 'react';
import { ensureSignedInWithFabric } from '@microsoft/rayfin-auth-provider-fabric';
import { client } from './lib/rayfin';

const fabricOptions = {
  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,
};

export function useFabricAuth() {
  const [session, setSession] = useState(client.auth.getSession());

  useEffect(() => client.auth.onSessionChange(setSession), []);

  // Signs in existing users and provisions new users on first sign-in.
  const signIn = useCallback(async () => {
    const result = await ensureSignedInWithFabric(client.auth, fabricOptions);
    setSession(result);
    return result;
  }, []);

  const signOut = useCallback(async () => {
    await client.auth.signOut();
  }, []);

  return {
    session,
    signIn,
    signOut,
    isAuthenticated: session?.isAuthenticated ?? false,
  };
}

コンポーネント内でフックを使用します。

function App() {
  const { isAuthenticated, signIn, signOut } = useFabricAuth();

  if (!isAuthenticated) {
    return <button onClick={signIn}>Sign in with Fabric</button>;
  }

  return (
    <>
      <Dashboard />
      <button onClick={signOut}>Sign out</button>
    </>
  );
}

API リファレンス

ensureSignedInWithFabric

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

4 段階の認証ウォーターフォールを実装します。

  1. 既に認証されている場合は、既存のセッションを返します。
  2. リフレッシュ トークンによるサイレント リフレッシュを試みます。
  3. 埋め込みモード — Fabric iframe 内で実行されている場合は、postMessageを介して親フレームにセッションを取得します。
  4. ポップアップ (ポップアップ フロー) でFabric ポータルを開き、postMessage ハンドオフを待機します。

手順 1 から 3 は、ページの読み込み時に安全に呼び出します。 手順 4. でポップアップが開き、ユーザー ジェスチャ ハンドラー内で実行する必要があります。

FabricAuthOptions

財産 タイプ Description
workspaceId string Fabric ワークスペースの IDです。
projectId string Fabric アプリ項目の ID。
fabricPortalUrl string Fabric ポータルのベース URL (例: https://app.fabric.microsoft.com)。
returnOrigin string postMessage 配信に使用するあなたのアプリの配信元(たとえば、window.location.origin)。 スキームとホストのみから成るオリジン(パスは含まない)である必要があります。
fabricEmbedded boolean (任意) 埋め込みモードを強制します。 URL 内の ?fabricEmbedded=true から自動検出されます。

補助関数

Function Description
initEmbeddedAuth(auth, options) ページ読み込みセーフな埋め込み認証。Fabric iframe 内で実行されている場合はセッションを返し、それ以外の場合は null返します。
initiateFabricLogin(auth, options) 低レベルのポップアップ フロー。 PKCE パラメーターを含むポップアップで Fabric ポータルを開き、postMessage ハンドオフを待機します。
isEmbeddedMode(options) アプリが埋め込みモード (Fabric iframe) で実行されている場合は、true を返します。

セキュリティ機能

  • PKCE S256 – すべてのフローで暗号コード検証ツールが生成され、承認コードの傍受を防ぐためのチャレンジが生成されます。
  • state ノンス – ランダムなノンスによってハンドオフ応答が元のタブに紐付けられ、クロスサイトリクエストフォージェリを防止します。
  • postMessage 配信元の検証 – SDK は受信メッセージの event.origin を検証し、予期しない配信元からのメッセージを拒否します。
  • 自動クリーンアップ – PKCEの状態は5分で期限切れとなり、次回のフロー時に回収されます。
  • フロー タイムアウト – ハンドオフ メッセージが受信されない場合、ポップアップ フローは 5 分後にタイムアウトします。

認証に関する問題のトラブルシューティング

ブラウザーによって、Fabric ポータル ウィンドウがブロックされました。 同期ユーザー ジェスチャ ハンドラー (ボタン ensureSignedInWithFabric() など) からonClickが呼び出されていることを確認します。 ユーザー操作の前に、ページ読み込み時または非同期チェーン内で呼び出さないでください。

セッションが保持されない

RayfinClientが正しいbaseUrlpublishableKeyで構成されていることを確認します。 コールバック タブと元のタブは、 BroadcastChannellocalStorage が機能するために同じ配信元を共有する必要があります。

長い遅延後に認証が失敗する

サインイン フローは 5 分後に期限切れになります。 サインイン プロセスを開始しても、その時間内に完了しなかった場合、フローは失敗します。 ポップアップを閉じ、もう一度サインイン ボタンを選択して新しいフローを開始します。