Configurar a página de ponte para redirecionamento no MSAL Browser

Este guia fornece instruções específicas do framework para configurar a página de ponte de redirecionamento introduzida no MSAL Browser v5. Para obter contexto sobre a razão pela qual a bridge de redirecionamento é necessária, consulte o guia de migração da v4 para a v5.

Warning

A página de ponte de redirecionamento não deve ser enviada com cabeçalhos Cross-Origin-Opener-Policy. A página bridge é um intermediário que recebe a resposta de autenticação após o IdP completar o fluxo OAuth. Se os cabeçalhos COOP estiverem definidos na página da ponte, o navegador efetua uma troca de grupo de contexto de navegação que interrompe o canal de comunicação com a aplicação principal — reintroduzindo exatamente o problema que a ponte foi concebida para resolver.

Importante

Depois de atualizares o teu redirectUri para apontar para a nova página da ponte de redirecionamento, DEVES também atualizar o URI de redirecionamento no registo da tua aplicação Entra ID. O URI deve corresponder exatamente — incluindo caminho, protocolo e porta. A falha em atualizar o registo da aplicação resultará em redirect_uri_mismatch erros.

Angular

  1. Crie o componente da ponte de redirecionamento (src/app/redirect/redirect.component.ts):
import { Component, OnInit } from "@angular/core";
import { broadcastResponseToMainFrame } from "@azure/msal-browser/redirect-bridge";

@Component({
    selector: "app-redirect",
    standalone: true,
    template: "<p>Processing authentication...</p>",
})
export class RedirectComponent implements OnInit {
    ngOnInit(): void {
        broadcastResponseToMainFrame().catch((error: Error) => {
            console.error("Error broadcasting response to main frame:", error);
        });
    }
}
  1. Adiciona a /redirect rota na tua configuração de roteamento. A rota de redirecionamento deve estar fora do MsalGuard, e a página de redirecionamento não deve fazer chamadas de API que desencadeiam MsalInterceptor (ou de outra forma invocassem APIs MSAL):
import { RedirectComponent } from "./redirect/redirect.component";

const routes: Routes = [
    { path: "redirect", component: RedirectComponent },
    // ... your other routes
];
  1. Assegura-te de que a build inclui o componente. Não é necessária qualquer alteração aos angular.json recursos ao utilizar um componente de rota do Angular — a CLI do Angular inclui automaticamente o componente no pacote. Se preferir um redirect.html estático em vez de um componente encaminhado por rota, adicione-o ao array assets:
// angular.json
{
    "projects": {
        "your-app": {
            "architect": {
                "build": {
                    "options": {
                        "assets": [
                            { "glob": "**/*", "input": "public" },
                            "src/redirect.html" // ← Add redirect bridge page
                        ]
                    }
                }
            }
        }
    }
}

Exemplo: Consulte angular-standalone-sample e angular-modules-sample.

Vite

O Vite requer uma configuração de várias páginas para que redirect.html seja incluído como um ponto de entrada separado no resultado da compilação.

  1. Criar redirect.html na raiz do seu projeto (ao lado de index.html):
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Redirect</title>
</head>
<body>
    <p>Processing authentication...</p>
    <script type="module">
        import { broadcastResponseToMainFrame } from "@azure/msal-browser/redirect-bridge";

        broadcastResponseToMainFrame().catch((error) => {
            console.error("Error broadcasting response:", error);
        });
    </script>
</body>
</html>
  1. Atualização vite.config.ts Para adicionar a página de redirecionamento como segunda entrada:
import { defineConfig } from "vite";
import { resolve } from "path";

export default defineConfig({
    build: {
        rollupOptions: {
            input: {
                main: resolve(__dirname, "index.html"),
                redirect: resolve(__dirname, "redirect.html"), // ← Redirect bridge entry
            },
        },
    },
});

Durante o desenvolvimento (vite dev), a página de redirecionamento é automaticamente servida em /redirect.html. Em compilações de produção, o Rollup emite tanto index.html como redirect.html no diretório de saída.

Exemplo: Veja o react-router-sample, typescript-sample e b2c-sample.

Webpack

O webpack requer um ponto de entrada dedicado e uma HtmlWebpackPlugin instância para a página de redirecionamento.

  1. Criar src/redirect.html:
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Redirect</title>
</head>
<body>
    <p>Processing authentication...</p>
    <!-- The redirect script bundle will be injected by HtmlWebpackPlugin (see redirect.js entry). -->
</body>
</html>
  1. Criar src/redirect.js (ponto de entrada para o Webpack):
import { broadcastResponseToMainFrame } from "@azure/msal-browser/redirect-bridge";

broadcastResponseToMainFrame().catch((error) => {
    console.error("Error broadcasting response:", error);
});
  1. Atualização webpack.config.js:
const HtmlWebpackPlugin = require("html-webpack-plugin");

module.exports = {
    entry: {
        main: "./src/index.js",
        redirect: "./src/redirect.js", // ← Redirect bridge entry
    },
    plugins: [
        new HtmlWebpackPlugin({
            filename: "index.html",
            template: "./src/index.html",
            chunks: ["main"],
        }),
        new HtmlWebpackPlugin({
            filename: "redirect.html",
            template: "./src/redirect.html",
            chunks: ["redirect"], // ← Only include the redirect chunk
        }),
    ],
};

Next.js

As páginas do Next.js transformam-se automaticamente em rotas, por isso a ponte de reencaminhamento é um componente de página. A configuração difere entre o Pages Router e o App Router.

Router de Páginas (pages/)

  1. Criar pages/redirect.js:
import { useEffect } from "react";
import { broadcastResponseToMainFrame } from "@azure/msal-browser/redirect-bridge";

export default function Redirect() {
    useEffect(() => {
        broadcastResponseToMainFrame().catch((error) => {
            console.error("Error broadcasting response to main frame:", error);
        });
    }, []);

    return <p>Processing authentication...</p>;
}
  1. Excluir a página de redirecionamento de MsalProvider em _app.js:
// pages/_app.js
import { useRouter } from "next/router";
import { MsalProvider } from "@azure/msal-react";

function MyApp({ Component, pageProps }) {
    const router = useRouter();

    // The redirect page must NOT be wrapped in MsalProvider
    if (router.pathname === "/redirect") {
        return <Component {...pageProps} />;
    }

    return (
        <MsalProvider instance={msalInstance}>
            <Component {...pageProps} />
        </MsalProvider>
    );
}

Router de Aplicações (app/)

  1. Criar app/redirect/page.js — isto deve ser um Componente Cliente ("use client"):
"use client";

import { useEffect } from "react";
import { broadcastResponseToMainFrame } from "@azure/msal-browser/redirect-bridge";

export default function Redirect() {
    useEffect(() => {
        broadcastResponseToMainFrame().catch((error) => {
            console.error("Error broadcasting response to main frame:", error);
        });
    }, []);

    return <p>Processing authentication...</p>;
}
  1. Exclua a rota de redirecionamento de MsalProvider na tua disposição raiz. Se o seu app/layout.js envolver filhos em MsalProvider, crie um layout separado para a rota de redirecionamento que a salta:
// app/redirect/layout.js — no MsalProvider wrapper
export default function RedirectLayout({ children }) {
    return <>{children}</>;
}

Isto impede que a MSAL processe o hash da resposta de autenticação antes de broadcastResponseToMainFrame() ser executado.


Não são necessárias next.config.js alterações para nenhum dos routers — o Next.js serve automaticamente as páginas.

Exemplo: Veja o exemplo nextjs para um exemplo de Pages Router.

Express.js / Node.js Backend

Ao usar o Express.js (ou qualquer backend Node.js que sirva ficheiros estáticos), configure o servidor para servir a página de redirecionamento sem cabeçalhos COOP:

const express = require("express");
const path = require("path");
const app = express();

// Serve the redirect bridge page WITHOUT COOP headers
app.get("/redirect", (req, res) => {
    res.sendFile(path.join(__dirname, "public", "redirect.html"));
});

// Set COOP headers for all other routes
app.use((req, res, next) => {
    res.setHeader("Cross-Origin-Opener-Policy", "same-origin");
    next();
});

app.use(express.static(path.join(__dirname, "public")));

Exemplo: Veja o HybridSample.

Recursos adicionais