Iniciar sesión de usuarios

Antes de empezar aquí, asegúrese de comprender cómo inicializar el objeto de aplicación.

Las API de inicio de sesión de MSAL recuperan un authorization code que se puede intercambiar por un token de identificador para un usuario que ha iniciado sesión, al tiempo que da su consentimiento a los ámbitos de un recurso adicional y un token de acceso que contiene los ámbitos con consentimiento del usuario para permitir que la aplicación llame de forma segura a la API.

Elección de un tipo de interacción

Vea aquí si no está seguro de las diferencias entre loginRedirect y loginPopup.

Inicio de sesión del usuario

Debe enviar un objeto de solicitud a las API de inicio de sesión. Este objeto permite usar parámetros diferentes en la solicitud. Consulte aquí para obtener más información sobre los parámetros del objeto de solicitud.

Para las solicitudes de inicio de sesión, todos los parámetros son opcionales, por lo que solo puede enviar un objeto vacío.

  • Popup
try {
    const loginResponse = await msalInstance.loginPopup({});
} catch (err) {
    // handle error
}
  • Redireccionar
try {
    msalInstance.loginRedirect({});
} catch (err) {
    // handle error
}

O bien, puede enviar un conjunto de ámbitos para obtener el consentimiento previo a:

  • Popup
var loginRequest = {
    scopes: ["user.read", "mail.send"] // optional Array<string>
};

try {
    const loginResponse = await msalInstance.loginPopup(loginRequest);
} catch (err) {
    // handle error
}
  • Redireccionar
var loginRequest = {
    scopes: ["user.read", "mail.send"] // optional Array<string>
};

try {
    msalInstance.loginRedirect(loginRequest);
} catch (err) {
    // handle error
}

API de cuentas

Cuando una llamada de inicio de sesión se ha realizado correctamente, puede usar la getAllAccounts() función para recuperar información sobre los usuarios que han iniciado sesión actualmente.

const myAccounts: AccountInfo[] = msalInstance.getAllAccounts();

Si conoce la información de la cuenta, también puede recuperar la información de la cuenta mediante la 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

El filtrado por username se proporciona para mayor comodidad y debe considerarse menos confiable que la búsqueda basada en homeAccountId. Cuando sea posible, use homeAccountId.

En escenarios de B2C, su inquilino de B2C debe estar configurado para devolver la emails reclamación sobre idTokens con el fin de utilizar el username filtro en la API getAccount().

Estas API devolverán un objeto de cuenta o una matriz de objetos de cuenta con la firma siguiente:

{
    // 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;
};

Inicio de sesión silencioso con ssoSilent()

Si ya tiene una sesión que existe con el servidor de autenticación, puede usar la API ssoSilent() para realizar solicitudes de tokens sin interacción.

Con sugerencia de usuario

Si ya tiene la información de inicio de sesión del usuario, puede pasarla a la API para mejorar el rendimiento y asegurarse de que el servidor de autorización buscará la sesión de cuenta correcta. Puede pasar uno de los siguientes elementos al objeto de solicitud para obtener correctamente un token de forma silenciosa.

Se recomienda aprovechar la login_hint reclamación opcional del token de identificación (proporcionada a ssoSilent como loginHint), ya que es la pista de cuenta más fiable para las solicitudes silenciosas (e interactivas).

  • account (que se puede recuperar mediante una de las API de la cuenta)
  • sid (que se puede recuperar del idTokenClaims de un objeto account)
  • login_hint (se pueden recuperar de las siguientes maneras)
    • Como la propiedad loginHint del objeto de cuenta (recomendado)
    • Como la reclamación de token de identificación login_hint del objeto de cuenta (recomendado)
    • Como la propiedad username del objeto de cuenta (no recomendado)
    • Como la reclamación de token de identificación upn del objeto de cuenta (no recomendado)

Note

Las propiedades username y upn son parcialmente compatibles en sustitución de la reclamación login_hint real, pero no se recomiendan. Utilice las propiedades de la cuenta loginHint o idTokenClaims.login_hint si están disponibles.

Al pasar una cuenta, se buscará primero la reclamación opcional de token de identificación login_hint (preferida), luego la reclamación opcional de token de identificación sid y, a continuación, se recurrirá a loginHint (si se proporciona) o al nombre de usuario de la cuenta.

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
    }
}

Sin sugerencia de usuario

Si no hay suficiente información disponible sobre el usuario, puede intentar usar la API ssoSilentsin pasar un account, sid o login_hint.

const silentRequest = {
    scopes: ["User.Read", "Mail.Read"]
};

Sin embargo, tenga en cuenta que, si su aplicación tiene rutas de código para varios usuarios en una única sesión del navegador, o si el usuario tiene varias cuentas en esa misma sesión del navegador, existe una mayor probabilidad de errores silenciosos de inicio de sesión. Es posible que aparezca el siguiente error en caso de varias sesiones de cuenta encontradas por el servidor de autorización:

InteractionRequiredAuthError: interaction_required: AADSTS16000: Either multiple user identities are available for the current request or selected account is not supported for the scenario.

Esto indica que el servidor no pudo determinar en qué cuenta iniciar sesión y requerirá uno de los parámetros anteriores (account, login_hint, sid) o un inicio de sesión interactivo para elegir la cuenta.

Warning

Cuando se usa ssoSilent, el servicio intenta cargar la página URI de redirección en un iframe incrustado invisible. Las directivas de seguridad de contenido y los valores de los encabezados HTTP presentes en la respuesta de la página URI de redireccionamiento de tu aplicación, como X-FRAME-OPTIONS: DENY y X-FRAME-OPTIONS: SAMEORIGIN, pueden impedir que tu aplicación se cargue en el iframe, bloqueando de hecho el SSO silencioso. Si piensa usar ssoSilent, asegúrese de que el URI de redirección apunta a una página que no implementa dichas directivas.

Consideraciones sobre RedirectUri

Todos los flujos de autenticación ahora requieren una página de redirección dedicada que implemente el puente de redirección de MSAL. Esto es necesario para dar soporte a las cabeceras COOP (Cross-Origin-Opener-Policy) y habilitar la comunicación segura entre las ventanas emergentes o las ventanas iframe y la aplicación principal.

Configuración de la página de redirección

Tu redirectUri debe apuntar a una página dedicada que cargue el script de puente de redireccionamiento. Esta página debe:

  1. Carga del script de puente de redirección : este script controla la comunicación con la ventana principal.
  2. No se incluyen javaScript excepto el script de puente : la página de redirección solo debe ejecutar el script de puente.
  3. No se incluye la lógica de enrutamiento : evite las bibliotecas de enrutadores que puedan interferir con el control de hash.
  4. Estar registrado en el registro de aplicaciones - El URI debe coincidir exactamente con el registrado en el portal de Azure

Página de redirección de ejemplo (cuando se usa un agrupador como Vite o 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

El @azure/msal-browser/redirect-bridge especificador debe resolverse mediante un agrupador (Vite, Webpack, etc.), no es una dirección URL que los exploradores pueden capturar directamente. Para obtener instrucciones específicas del marco, consulte la guía de configuración del puente de redirección.

Configuración

Puede establecer el redirectUri globalmente en la configuración de MSAL o para cada solicitud:

Configuración global:

const msalConfig = {
    auth: {
        clientId: "your-client-id",
        authority: "https://login.microsoftonline.com/common",
        redirectUri: "http://localhost:3000/redirect"
    }
};

const msalInstance = new PublicClientApplication(msalConfig);

Configuración por solicitud:

msalInstance.loginPopup({
    scopes: ["user.read"],
    redirectUri: "http://localhost:3000/redirect"
});

Para obtener más información y completar implementaciones de ejemplo, consulte:

Administración de errores emergentes de interaction_in_progress

En el caso de los flujos con ventana emergente, puede usar la marca overrideInteractionInProgress para cancelar una interacción pendiente e iniciar una nueva. Esto es útil para escenarios de recuperación en los que el usuario canceló un elemento emergente o se produjo un error de interacción.

Note

Esta característica solo está disponible para los flujos emergentes y no se admite para los flujos de redirección. Con el encabezado COOP (Cross-Origin-Opener-Policy), la conexión tradicional window.opener se corta, de modo que las ventanas emergentes solo pueden comunicarse con la ventana principal a través de BroadcastChannel.

Importante

Si se establece este valor en true, se cancelará de forma forzosa cualquier solicitud pendiente de autenticación mediante ventana emergente, pero no se cerrarán las ventanas emergentes abiertas.

Cuando se establece en true:

  • Si ya hay otra interacción con una ventana emergente en curso, se cancela forzosamente, pero las ventanas emergentes abiertas no se cierran.
  • La interacción pendiente se rechaza con un error interaction_in_progress_cancelled
  • El nuevo flujo de la ventana emergente se inicia inmediatamente

Casos de uso válidos:

  • Recuperarse de errores en los que el usuario canceló una ventana emergente (la ventana emergente se cerró sin completar el proceso de autenticación)
  • Implementación de flujos de recuperación de errores personalizados
  • Ofrecer un mecanismo para reintentar tras un error en la interacción con la ventana emergente

Valor predeterminado:false

Importante: Usar solo al hacer clic en el botón

No vuelva a intentarlo automáticamente al detectar un interaction_in_progress error. La anulación debe solo activarse por una acción explícita del usuario (como hacer clic en un botón "Reintentar"). La anulación automática de interacciones puede dar lugar a:

  • Condiciones de carrera entre varios flujos de autenticación
  • Cancelaciones inesperadas de intentos de autenticación legítimos
  • Experiencia de usuario deficiente con flujos de autenticación que se inician y detienen inesperadamente
  • Muchas ventanas emergentes abiertas que no dan lugar a respuestas de autenticación satisfactorias

Ejemplo: Control de errores adecuado con el reintento desencadenado por el usuario

Para obtener implementaciones completas con comentarios visuales, consulte:

Ambos ejemplos muestran lo siguiente:

  • Mensaje de advertencia que se muestra durante la autenticación emergente
  • Vuelve a intentar el modal/diálogo con una explicación clara cuando se produzca un error interaction_in_progress
  • Administración de estado adecuada para el reintento desencadenado por el usuario
  • Componentes de interfaz de usuario listos para producción
// 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
}

Ejemplo: componente React con reintento activado por el usuario

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

Pasos siguientes

Aprenda a adquirir y usar un token de acceso.