oauth-2.0azure-active-directorywebformsopenid-connectowin

Azure AD auth token refresh request blocked in iframe


We have a legacy Webforms application running on .NET framework 4.8 and recently updated to use Azure/Entra authentication.

We used all of the code templates and articles provided by MS as the starting point and everything is working fine with one major issue so far.

The ID token we receive during authentication contains an expiry as expected, however when Owin detects the expiry it sends a request to login.microsoft.com to refresh the token. This also works as expected "except" when the page requested is sitting in an iframe

When the page is inside an iframe and the ID token has expired we get this error

Refused to display 'https://login.microsoftonline.com/' in a frame because it set 'X-Frame-Options' to 'deny'

What's strange is the SecurityTokenValidated event does fire, but it seems to get stuck in a loop and fires repeatedly, then eventually shows a broken link where the iframe was loaded and the above message.

I can understand not showing the full login screen inside an iframe however in this case all it's doing is refreshing the token with no interaction needed from the user, it just needs to send back the updated auth cookie.

Below is our Owin startup code for reference

Public Sub ConfigureAuth(ByVal app As IAppBuilder)

        app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType)

        app.UseCookieAuthentication(New CookieAuthenticationOptions() With {.CookieSameSite = SameSiteMode.Lax, .CookieName = "appname.Auth"})

        app.UseOpenIdConnectAuthentication(New OpenIdConnectAuthenticationOptions() With {
            .ClientId = clientId,
            .Authority = authority,
            .RedirectUri = redirectUri,
            .PostLogoutRedirectUri = postLogoutRedirectUri,
            .Notifications = New OpenIdConnectAuthenticationNotifications() With {
                .AuthenticationFailed = Function(context) System.Threading.Tasks.Task.FromResult(0),
                .SecurityTokenValidated = Function(context)
                                              Return OnSecurityTokenValidated(context)
                                          End Function
            }}
        )

        app.UseStageMarker(PipelineStage.Authenticate)

    End Sub

Solution

  • These days you cannot use third party cookies (or OAuth flows that use them) in iframes. They will be dropped due to browser restrictions introduced in updates to RFC6265.

    For example, there used to be an iframe flow used by SPAs, described in my blog post, used to refresh access tokens. The OpenID Connect prompt=none parameter could prevent iframes from hanging. Applications have had to stop using this flow, since cookies required for it to work are now dropped.

    The cookie restrictions are there to protect user privacy and keep the user informed, so they are a good thing. The best way to solve your problem is to always run OAuth redirects on the top level window. The user then provides credentials to a visible domain, shown in the browser bar. The browser will then no longer drop OAuth cookies, due to the user being informed.