Skip to content
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "major",
"comment": "Remove onRedirectNavigate from endSessionRequest #8066",
"packageName": "@azure/msal-browser",
"email": "[email protected]",
"dependentChangeType": "patch"
}
1 change: 0 additions & 1 deletion lib/msal-browser/apiReview/msal-browser.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -561,7 +561,6 @@ export type EndSessionPopupRequest = Partial<Omit<CommonEndSessionRequest, "toke
// @public
export type EndSessionRequest = Partial<Omit<CommonEndSessionRequest, "tokenQueryParameters">> & {
authority?: string;
onRedirectNavigate?: (url: string) => boolean | void;
};

// Warning: (ae-missing-release-tag) "EventCallbackFunction" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal)
Expand Down
37 changes: 20 additions & 17 deletions lib/msal-browser/docs/logout.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,18 +60,25 @@ await msalInstance.logoutRedirect({
```

### Skipping the server sign-out

**WARNING:** Skipping the server sign-out means the user's session will remain active on the server and can be signed back into your application without providing credentials again.

If you want your application to only perform local logout you can provide a callback to the `onRedirectNavigate` parameter on the request and have the callback return false.
If you want your application to only perform local logout you can provide a callback to the `onRedirectNavigate` parameter in the configuration and have the callback return false.

```javascript
msalInstance.logoutRedirect({
onRedirectNavigate: (url) => {
// Return false if you would like to stop navigation after local logout
return false;
const msalConfig = {
auth: {
clientId: 'your_client_id',
authority: 'https://login.microsoftonline.con/{your_tenant_id}',
redirectUri: 'https://contoso.com',
postLogoutRedirectUri: 'https://contoso.com/homepage',
onRedirectNavigate: (url) => {
// Return false if you would like to stop navigation after local logout
return false;
}
}
});
};
const msalInstance = new PublicClientApplication(msalConfig);
msalInstance.logoutRedirect();
```

## logoutPopup
Expand Down Expand Up @@ -151,30 +158,26 @@ Example:
```typescript
const msal = new PublicClientApplication({
auth: {
clientId: "my-client-id"
clientId: "my-client-id",
onRedirectNavigate: (url) => {
return false;
}
},
system: {
allowRedirectInIframe: true
}
})

// Automatically on page load
msal.logoutRedirect({
onRedirectNavigate: () => {
// Return false to stop navigation after local logout
return false;
}
});
msal.logoutRedirect();
```

Now when a user logouts out of another application, your application's front-channel logout url will be loaded in a hidden iframe, and MSAL.js will clear its cache to complete single-sign out.

Please note that front-channel logout is not always supported across browsers. Chromium enabled [Storage Partitioning](https://privacysandbox.google.com/cookies/storage-partitioning) and Firefox supports [similar standard](https://developer.mozilla.org/en-US/docs/Web/Privacy/Guides/State_Partitioning) limiting applications to execute front-channel logout. For official Entra documentation on this topic, see [here](https://learn.microsoft.com/en-us/entra/identity-platform/reference-third-party-cookies-spas#limitations-on-front-channel-logout-without-third-party-cookies).

### Front-channel logout samples

The following samples demonstrate how to implement front-channel logout using MSAL.js:

- MSAL Angular v2: [Angular 11 sample](https://github.com/AzureAD/microsoft-authentication-library-for-js/tree/dev/samples/msal-angular-v2-samples/angular11-sample-app)
- MSAL React: [React Router sample](https://github.com/AzureAD/microsoft-authentication-library-for-js/tree/dev/samples/msal-react-samples/react-router-sample)

## Events
Expand Down
2 changes: 1 addition & 1 deletion lib/msal-browser/docs/v4-migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ See the [Configuration doc](./configuration.md#system-config-options) for more d

### Removal of `onRedirectNavigate` parameter

The `onRedirectNavigate` parameter has been removed from the `RedirectRequest` object. It has *not* been removed from the `Configuration` object and can continue to be set there.
The `onRedirectNavigate` parameter will *only be supported* from `Configuration` object going forward and is removed from `RedirectRequest` and `EndSessionRequest` objects. Please ensure to set it in msal config if you need to use it.

## Behavioral Breaking Changes

Expand Down
113 changes: 23 additions & 90 deletions lib/msal-browser/src/interaction_client/RedirectClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -790,36 +790,16 @@ export class RedirectClient extends StandardInteractionClient {
account: (logoutRequest && logoutRequest.account) || undefined,
});

// Create a serializable version of the request for events
const {
// @ts-ignore
// eslint-disable-next-line @typescript-eslint/no-unused-vars
onRedirectNavigate,
...serializableLogoutRequest
} = validLogoutRequest;

if (authClient.authority.protocolMode === ProtocolMode.OIDC) {
try {
authClient.authority.endSessionEndpoint;
} catch {
if (validLogoutRequest.account?.homeAccountId) {
if (
// @ts-ignore
typeof validLogoutRequest.onRedirectNavigate ===
"function"
) {
this.eventHandler.emitEvent(
EventType.LOGOUT_SUCCESS,
InteractionType.Redirect,
serializableLogoutRequest
);
} else {
this.eventHandler.emitEvent(
EventType.LOGOUT_SUCCESS,
InteractionType.Redirect,
validLogoutRequest
);
}
this.eventHandler.emitEvent(
EventType.LOGOUT_SUCCESS,
InteractionType.Redirect,
validLogoutRequest
);
return;
}
}
Expand All @@ -830,69 +810,27 @@ export class RedirectClient extends StandardInteractionClient {
authClient.getLogoutUri(validLogoutRequest);

if (validLogoutRequest.account?.homeAccountId) {
if (
// @ts-ignore
typeof validLogoutRequest.onRedirectNavigate === "function"
) {
this.eventHandler.emitEvent(
EventType.LOGOUT_SUCCESS,
InteractionType.Redirect,
serializableLogoutRequest
);
} else {
this.eventHandler.emitEvent(
EventType.LOGOUT_SUCCESS,
InteractionType.Redirect,
validLogoutRequest
);
}
this.eventHandler.emitEvent(
EventType.LOGOUT_SUCCESS,
InteractionType.Redirect,
validLogoutRequest
);
}
// Check if onRedirectNavigate is implemented, and invoke it if so
if (
logoutRequest &&
typeof logoutRequest.onRedirectNavigate === "function"
) {
const navigate = logoutRequest.onRedirectNavigate(logoutUri);

if (navigate !== false) {
this.logger.verbose(
"Logout onRedirectNavigate did not return false, navigating",
this.correlationId
);
// Ensure interaction is in progress
if (!this.browserStorage.getInteractionInProgress()) {
this.browserStorage.setInteractionInProgress(
true,
INTERACTION_TYPE.SIGNOUT
);
}
await this.navigationClient.navigateExternal(
logoutUri,
navigationOptions
);
return;
} else {
// Ensure interaction is not in progress
this.browserStorage.setInteractionInProgress(false);
this.logger.verbose(
"Logout onRedirectNavigate returned false, stopping navigation",
this.correlationId
);
}
} else {
// Ensure interaction is in progress
if (!this.browserStorage.getInteractionInProgress()) {
this.browserStorage.setInteractionInProgress(
true,
INTERACTION_TYPE.SIGNOUT
);
}
await this.navigationClient.navigateExternal(
logoutUri,
navigationOptions
// Ensure interaction is in progress
if (!this.browserStorage.getInteractionInProgress()) {
this.browserStorage.setInteractionInProgress(
true,
INTERACTION_TYPE.SIGNOUT
);
return;
}
await this.navigationClient.navigateExternal(
logoutUri,
navigationOptions
);
this.eventHandler.emitEvent(
EventType.LOGOUT_END,
InteractionType.Redirect
);
} catch (e) {
if (e instanceof AuthError) {
(e as AuthError).setCorrelationId(this.correlationId);
Expand All @@ -910,11 +848,6 @@ export class RedirectClient extends StandardInteractionClient {
);
throw e;
}

this.eventHandler.emitEvent(
EventType.LOGOUT_END,
InteractionType.Redirect
);
}

/**
Expand Down
2 changes: 0 additions & 2 deletions lib/msal-browser/src/request/EndSessionRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,10 @@ import { CommonEndSessionRequest } from "@azure/msal-common/browser";
* - authority - Authority to send logout request to.
* - correlationId - Unique GUID set per request to trace a request end-to-end for telemetry purposes.
* - idTokenHint - ID Token used by B2C to validate logout if required by the policy
* - onRedirectNavigate - Callback that will be passed the url that MSAL will navigate to. Returning false in the callback will stop navigation.
* - logoutHint - A string that specifies the account that is being logged out in order to skip the server account picker on logout
*/
export type EndSessionRequest = Partial<
Omit<CommonEndSessionRequest, "tokenQueryParameters">
> & {
authority?: string;
onRedirectNavigate?: (url: string) => boolean | void;
};
Loading