What does KMSI in Azure B2C actually DO?
Asked Answered
C

1

10

We've got this document that explains how to set up Keep Me Signed In (KMSI) using Custom Policy: https://learn.microsoft.com/en-us/azure/active-directory-b2c/custom-policy-keep-me-signed-in

OK, great, so we now know how to use (annoyingly complex) XML policy files to set up some UI for a checkbock. But what is this actually doing? Where is the info on this?

  • Is it providing the client a new ID Token without re-auth?
  • Is it providing a new auth_code?
  • Is it using a hidden i-frame?
  • How is a refresh actually called/accomplished from the client app? (SPA)
  • Is a round-trip to B2C needed and it just doesnt ask the user for creds and redirects them right back to the app? Or is the app able to make a refresh request completely UI/UX silent? If so, how? Where is the API? Is something in MSAL.js needed?
  • Why local only? If B2C is the "middle man" IDP, and the tokens it issues are its own (not actually from a social account, of course), then why can't it refresh tokens this way for all account types (local or social)?

My understanding is that, for Implicit Grant, storing Refresh Token was not possible, so keeping a session cookie around and using it to acquire a new session via i-frame with prompt=none was a HACK to be able to keep a session cookie updated and current.

Here is an article by former MS (now Auth0) identity guru Vittorio: https://auth0.com/blog/oauth2-implicit-grant-and-spa/

He mentions "Renewing Access Tokens" by Refresh Token Rotation. This is described as:

"a feature that invalidates a refresh token and issues a new one whenever it is used to refresh an access token"

This appears to be accomplished by a session cookie and i-frame "hack" (as was used with Implicit Grant), which returns a new authorization code, which (presumably) can be used to get a new Access Token.

Why is this needed when we now have PKCE? Apparently it is still bad to store long-lived Refresh Tokens in the browser, even with PKCE. I found undocumented information that B2C Refresh Tokens for SPA max lifetime is 24 hours (not 90 days, and not configurable).

So are we still doing this session cookie hidden i-frame hack today? Even with PKCE? And is that what B2C KMSI is doing? If so, how is it triggered, and how does my app actually get a new Access Token for use with my API?

Bottom line: I need to keep my users signed and able to access my secured web APIs without re-auth even if they dont open my app again for 100+ days. And ideally this should be accomplished completely silently, no round trip, regardless of whether the account was local or social on the IDP side. Is the B2C KMSI feature the right mechanism for this?

Continue answered 15/11, 2020 at 22:37 Comment(0)
J
18

KMSI/No KMSI effects how AAD B2C sets its web session cookie on the client.

KMSI: Sets a persistent session cookies for a period you want. It means the user doesn’t need to re-present credentials to AAD B2C the next time they visit your website, even if they closed the browser. The maximum time you can set this to is around 65yrs.

No KMSI: Sets a session cookie (non persistent). Users have to present their credentials to AAD B2C the next time they visit your website if they closed the browser. If they didn’t close the browser, just the tab, the maximum time that they can login without re-presenting credentials for your website is 24hrs.

KMSI + Implicit flow (SPA) - Above rules apply to the login and the token renewal operations. A hidden iframe is used and relies on the AAD B2C cookie. Uses a hidden iframe which uses the AAD B2C session cookie to issue a new AT.

KMSI + PKCE (SPA) - Above rules ignored for token renewals where the refresh token is valid. Above rules only apply if the Refresh Token expired or doesn’t exist, this is the fallback. Otherwise, they don’t apply since Refresh token flow doesn’t rely on cookies. Max 24hr refresh token. Uses a hidden iframe and the OIDC refresh token flow is processed. But when the AAD B2C session cookie is processed, you will get a new Auth Code.

KMSI + Code/PKCE (Web App) - Above rules ignored for token renewals where the refresh token is valid. Above rules only apply if the Refresh Token expired or doesn’t exist. Otherwise, they don’t apply since Refresh token doesn’t rely on cookies. Max refresh token 90days after which you fall back to the cookie. But when the AAD B2C session cookie is processed, you will get a new Auth Code.

KMSI doesn’t work for social accounts because AAD B2C always relies on the social accounts session. It would be a security flaw if AAD B2C kept you signed in but your account was deleted at the federated IdP. You can tweak the session management to ignore calling back to a social IdP, but there is no UX to select KMSI for a social IdP nor can it be done programmatically today.

Since KMSI revolves around session cookies, it’s evaluated only when a round trip to AAD B2C is performed. That is when your refresh token expired (Code/PKCE flow) or you want a new access token (Implicit), or you’re doing a fresh logon. These scenarios involve a round trip where the AAD B2C session cookie is processed.

You do not need to configure MSAL in any way to tie with your KMSI config. AAD B2C itself processes cookies when required.

Since you’re using SPA + PKCE, you want to maximise the session lifetime as it is the fallback to the RT flow (max 24hrs), but the session lifetime is also only max 24hrs. So you’re forced to use KMSI to give you up to 65yrs session lifetime, at a cost that this session persists even after the browser was closed. There will be a hidden iframe to obtain a new access token each time it (AT) expires (max 24hrs) using the refresh token or cookie if the RT expired too (max 24hrs).

How is it triggered - MSAL library knows the validity of the Access Token and performs the required refresh token calls when needed. AAD B2C validates the RT, and otherwise falls back to the session cookie. So there are no code changes needed to accommodate any of this logic.

Every single call to your API in your SPA should call acquireTokenSilent() with the appropriate scopes prior to the API request itself. MSAL determines if a valid AT exists and only then makes a network request if one does not.

Joggle answered 15/11, 2020 at 23:57 Comment(2)
Excellent info and complete summary of this entire landscape, thank you! Regarding that last point with MSAL and acquireTokenSilent(), can you expound on the result? If both AT and RT are expired, does it make this call in an i-frame and the user is not actually redirected? And does this simply result in a new AT+RT to local token cache and I then proceed with my API call? And for social IDP, does acquireTokenSilent() result in a session length defined by the social provider, or does it result in a max of 24 hr session for the user?Continue
If both AT and RT are expired, does it make this call in an i-frame and the user is not actually redirected? -> Correct, itll use the iframe and cookies as fallback. And does this simply result in a new AT+RT to local token cache and I then proceed with my API call? Correct. And for social IDP, does acquireTokenSilent() result in a session length defined by the social provider, or does it result in a max of 24 hr session for the user? In this case, we rely on the Social IdP, there is a redirect to the Social IdP in the iframe too, and rely on their cookies instead of ours for better security.Joggle

© 2022 - 2024 — McMap. All rights reserved.