ここで開始する前に、 アプリケーション オブジェクトを初期化する方法を理解していることを確認してください。
MSAL のログイン API は、サインインしているユーザーについて、ID token と交換できる authorization code を取得します。また、追加のリソースに対するスコープへの同意とともに、ユーザーが同意したスコープを含む access token を取得し、これによりアプリは API を安全に呼び出すことができます。
相互作用の種類の選択
とloginRedirectの違いがわからない場合は、loginPopup参照してください。
ユーザーにログインする
ログイン API に要求オブジェクトを渡す必要があります。 このオブジェクトを使用すると、要求で異なるパラメーターを使用できます。 要求オブジェクトのパラメーターの詳細については、 こちらを 参照してください。
ログイン要求の場合、すべてのパラメーターは省略可能であるため、空のオブジェクトを送信できます。
- Popup
try {
const loginResponse = await msalInstance.loginPopup({});
} catch (err) {
// handle error
}
- リダイレクト
try {
msalInstance.loginRedirect({});
} catch (err) {
// handle error
}
または、一連の スコープ を送信して、次の内容に事前に同意することもできます。
- Popup
var loginRequest = {
scopes: ["user.read", "mail.send"] // optional Array<string>
};
try {
const loginResponse = await msalInstance.loginPopup(loginRequest);
} catch (err) {
// handle error
}
- リダイレクト
var loginRequest = {
scopes: ["user.read", "mail.send"] // optional Array<string>
};
try {
msalInstance.loginRedirect(loginRequest);
} catch (err) {
// handle error
}
アカウント API
ログイン呼び出しが成功したら、 getAllAccounts() 関数を使用して、現在サインインしているユーザーに関する情報を取得できます。
const myAccounts: AccountInfo[] = msalInstance.getAllAccounts();
アカウント情報がわかっている場合は、 getAccount() API を使用してアカウント情報を取得することもできます。
const username = "test@contoso.com";
const myAccount: AccountInfo = msalInstance.getAccount({ username });
const homeAccountId = "userid.hometenantid"; // Best to retrieve the homeAccountId from an account object previously obtained through msal
const myAccount: AccountInfo = msalInstance.getAccount({ homeAccountId });
Note
usernameによるフィルター処理は便宜上提供されており、homeAccountIdに基づく検索よりも信頼性が低いと見なす必要があります。 可能な場合は、homeAccountId を使用します。
B2C シナリオでは、emails API で idTokens フィルターを使用するために、usernameでgetAccount()要求を返すように B2C テナントを構成する必要があります。
これらの API は、次のシグネチャを持つアカウント オブジェクトまたはアカウント オブジェクトの配列を返します。
{
// home account identifier for this account object
homeAccountId: string;
// Entity who issued the token represented as a full host of it (e.g. login.microsoftonline.com)
environment: string;
// Full tenant or organizational id that this account belongs to
tenantId: string;
// preferred_username claim of the id_token that represents this account.
username: string;
};
ssoSilent() を使用したサイレント ログイン
認証サーバーとのセッションが既に存在する場合は、ssoSilent() API を使用して、対話なしでトークンの要求を行うことができます。
ユーザーヒント付き
ユーザーのサインイン情報が既にある場合は、これを API に渡してパフォーマンスを向上させ、承認サーバーが正しいアカウント セッションを探すようにすることができます。 トークンをサイレントモードで正常に取得するために、次のいずれかを要求オブジェクトに渡すことができます。
login_hintオプションの ID トークン要求 (ssoSilentとしてloginHintに提供) を利用することをお勧めします。これは、サイレント (および対話型) 要求の最も信頼性の高いアカウント ヒントであるためです。
-
account(アカウント API のいずれかを使用して取得できます) -
sid(idTokenClaimsオブジェクトのaccountから取得できます) -
login_hint(次の方法で取得できます)- アカウント オブジェクトの
loginHintプロパティとして (推奨) - アカウント オブジェクトの
login_hintID トークン要求として (推奨) - アカウント オブジェクトの
usernameプロパティとして (推奨されません) - アカウント オブジェクトの
upnID トークン要求として (推奨されません)
- アカウント オブジェクトの
Note
usernameプロパティとupnプロパティは、実際のlogin_hint要求の代わりに部分的にサポートされていますが、推奨されません。 使用可能な場合は、 loginHint または idTokenClaims.login_hint アカウントのプロパティを使用します。
アカウントを渡すと、まず login_hint のオプションの ID トークン クレーム (推奨) を探し、次に sid のオプションの id トークン クレームを探し、最後に loginHint (指定されている場合) またはアカウントのユーザー名にフォールバックします。
const account = msalInstance.getAllAccounts()[0];
const silentRequest = {
scopes: ["User.Read", "Mail.Read"],
loginHint: account.loginHint, // alternatively, account.idTokenClaims.login_hint
};
try {
const loginResponse = await msalInstance.ssoSilent(silentRequest);
} catch (err) {
if (err instanceof InteractionRequiredAuthError) {
const loginResponse = await msalInstance.loginPopup(silentRequest).catch(error => {
// handle error
});
} else {
// handle error
}
}
ユーザー ヒントなし
ユーザーに関する十分な情報がない場合は、ssoSilent、、またはaccountを渡sid、login_hint API の使用を試みることができます。
const silentRequest = {
scopes: ["User.Read", "Mail.Read"]
};
ただし、アプリケーションが 1 つのブラウザー セッションで複数のユーザーのコード パスを持っている場合、またはユーザーがその 1 つのブラウザー セッションに対して複数のアカウントを持っている場合は、サイレント サインイン エラーが発生する可能性が高くなります。 承認サーバーによって複数のアカウント セッションが見つかった場合、次のエラーが表示されることがあります。
InteractionRequiredAuthError: interaction_required: AADSTS16000: Either multiple user identities are available for the current request or selected account is not supported for the scenario.
これは、サーバーがサインインするアカウントを判断できなかったことを示し、アカウントを選択するには、上記のパラメーター (account、 login_hint、 sid) または対話型サインインのいずれかが必要になります。
Warning
ssoSilentを使用すると、サービスは非表示の埋め込み iframe にリダイレクト URI ページを読み込もうとします。 アプリのリダイレクト URI ページ応答に存在するコンテンツ セキュリティ ポリシーと HTTP ヘッダー値 ( X-FRAME-OPTIONS: DENY や X-FRAME-OPTIONS: SAMEORIGINなど) は、アプリが iframe に読み込まれるのを防ぎ、サイレント SSO を効果的にブロックする可能性があります。
ssoSilentを使用する場合は、リダイレクト URI がそのようなポリシーを実装していないページを指していることを確認します。
RedirectUri に関する考慮事項
すべての認証フローに 、MSAL リダイレクト ブリッジを実装する専用のリダイレクト ページが必要になりました。 これは、COOP (クロスオリジン -Opener-Policy) ヘッダーをサポートし、ポップアップ/iframe ウィンドウとメイン アプリケーション間の安全な通信を可能にするために必要です。
リダイレクト ページの設定
redirectUriは、リダイレクト ブリッジ スクリプトを読み込む専用ページを指す必要があります。 このページは次のとおりである必要があります:
- リダイレクト ブリッジ スクリプトを読み込む - このスクリプトはメイン ウィンドウとの通信を処理します
- ブリッジ スクリプトを除く JavaScript を含まない - リダイレクト ページでは、ブリッジ スクリプトのみを実行する必要があります
- ルーティング ロジックを含まない - ハッシュ処理を妨げる可能性のあるルーター ライブラリを回避する
- アプリ登録に登録する - URI は、Azure ポータルに登録されているものと正確に一致する必要があります
リダイレクト ページの例 (Vite や Webpack などのバンドルを使用する場合):
<!DOCTYPE html>
<html>
<head>
<title>Redirect</title>
</head>
<body>
<p>Processing authentication...</p>
<script type="module">
import { broadcastResponseToMainFrame } from "@azure/msal-browser/redirect-bridge";
broadcastResponseToMainFrame();
</script>
</body>
</html>
Note
@azure/msal-browser/redirect-bridge指定子は、バンドル (Vite、Webpack など) によって解決する必要があります。ブラウザーが直接フェッチできる URL ではありません。 フレームワーク固有の手順については、 リダイレクト ブリッジのセットアップ ガイドを参照してください。
コンフィギュレーション
redirectUri は、MSAL の構成でグローバルに設定することも、リクエストごとに設定することもできます。
グローバル構成:
const msalConfig = {
auth: {
clientId: "your-client-id",
authority: "https://login.microsoftonline.com/common",
redirectUri: "http://localhost:3000/redirect"
}
};
const msalInstance = new PublicClientApplication(msalConfig);
要求ごとの構成:
msalInstance.loginPopup({
scopes: ["user.read"],
redirectUri: "http://localhost:3000/redirect"
});
詳細と完全なサンプル実装については、次を参照してください。
ポップアップ interaction_in_progress エラーの処理
ポップアップ フローの場合は、 overrideInteractionInProgress フラグを使用して保留中の対話を取り消し、新しい操作を開始できます。 これは、ユーザーがポップアップを取り消したか、操作が失敗した回復シナリオに役立ちます。
Note
この機能は ポップアップ フローでのみ使用でき 、 リダイレクト フローではサポートされていません。 COOP (Cross-Origin-Opener-Policy) ヘッダーを使用すると、従来の window.opener 接続が切断され、ポップアップ ウィンドウが BroadcastChannel 経由でのみメイン フレームと通信できるようになります。
Important
これを true に設定すると、保留中のポップアップ認証要求は強制的に取り消されますが、開いているポップアップは閉じ られません 。
trueに設定する場合:
- 別のポップアップ操作が現在進行中の場合、強制的に取り消されますが、開いているポップアップは閉じられません
- 保留中の対話が
interaction_in_progress_cancelledエラーで拒否される - 新しいポップアップ フローはすぐに続行されます
有効なユース ケース:
- ユーザーがポップアップをキャンセルしたエラーからの復旧 (認証を完了せずにポップアップが閉じられました)
- カスタム エラー復旧フローの実装
- ポップアップ操作の失敗後に "再試行" メカニズムを提供する
既定:false
重要: ボタン クリック時にのみ使用する
エラーをキャッチするときにinteraction_in_progress。 オーバーライドは、明示的なユーザー アクション ([再試行] ボタンのクリックなど) によってのみ トリガーする必要があります。 インタラクションを自動的にオーバーライドすると、次の問題が発生する可能性があります。
- 複数の認証フロー間の競合状態
- 正当な認証試行の予期しないキャンセル
- 認証フローの開始と停止が予期せず行われ、ユーザー エクスペリエンスが低下する
- 正常な認証応答に至らない、開いたままのポップアップが多数ある
例: ユーザーによってトリガーされた再試行による適切なエラー処理
視覚的なフィードバックを使用した完全な実装については、次を参照してください。
- Express Sample — カスタム CSS を使用した JavaScript の実装を示します
- React Router サンプル — Material-UI コンポーネントを使用した React の実装を示します
どちらのサンプルも次の例を示しています。
- ポップアップ認証中に表示される警告メッセージ
- エラーが発生したときに明確な説明を含むモーダル/ダイアログ
interaction_in_progress再試行する - ユーザーによってトリガーされる再試行の適切な状態管理
- 運用対応 UI コンポーネント
// State to track if user wants to retry
let userWantsRetry = false;
// Button click handler
async function handleLoginClick() {
try {
const loginRequest = {
scopes: ["user.read"]
};
// If user explicitly clicked retry, override the existing interaction
if (userWantsRetry) {
loginRequest.overrideInteractionInProgress = true;
userWantsRetry = false; // Reset flag
}
const response = await msalInstance.loginPopup(loginRequest);
// Handle successful login
} catch (error) {
if (error.errorCode === 'interaction_in_progress') {
// Show retry button to user - DO NOT automatically retry
showRetryButton();
} else {
// Handle other errors
console.error(error);
}
}
}
// Retry button click handler
function handleRetryClick() {
userWantsRetry = true; // Set flag for next login attempt
handleLoginClick(); // User explicitly requested retry
}
例: ユーザーによってトリガーされた再試行を含む React コンポーネント
function LoginButton() {
const { instance } = useMsal();
const [showRetry, setShowRetry] = useState(false);
const [retryRequested, setRetryRequested] = useState(false);
const handleLogin = async () => {
try {
const loginRequest = {
scopes: ["user.read"],
// Only override if user clicked the retry button
overrideInteractionInProgress: retryRequested
};
setRetryRequested(false); // Reset retry flag
const response = await instance.loginPopup(loginRequest);
setShowRetry(false);
} catch (error) {
if (error.errorCode === 'interaction_in_progress') {
// Show retry button - let user decide whether to retry
setShowRetry(true);
} else {
console.error(error);
}
}
};
const handleRetry = () => {
setRetryRequested(true); // User explicitly requested retry
handleLogin();
};
return (
<div>
<button onClick={handleLogin}>Login</button>
{showRetry && (
<button onClick={handleRetry}>
Retry Login (Cancel Pending)
</button>
)}
</div>
);
}
次のステップ
アクセス トークンを取得して使用する方法について説明します。