https://leastprivilege.com/2020/03/31/spas-are-dead/ leastprivilege.com Dominick Baier on Identity & Access Control [cropped-20110730-img_3322-edit] Skip to content * Home * Training * Open Source * Pluralsight * Publications * Archive * About * Photography - Online Workshops in 2020 Major Update to IdentityModel.OidcClient - SPAs are dead!? Posted on March 31, 2020 by Dominick Baier clickbait isn't it? But this was Brock's immediate reaction when we saw (and I recommend you read this first): Full Third-Party Cookie Blocking and More What this basically means is, that browser are getting more and more strict with how they handle their cookies. The reasons are security (see the recent SameSite changes) and in this case - privacy. Cookies have been exploited for a long time one way or the other - and this is now the reaction of browser vendors. What does that mean to application architectures? Well - first of all - all these changes only affect cross-site scenarios. But if you are in that situation the immediate consequences will be: * front-channel logout notifications do not work anymore (used in pretty much every authentication protocol - like SAML, WS-Fed and OpenID Connect) * the OpenID Connect JavaScript session notifications don't working anymore * the "silent renew" technique that was recommended so far to give your application session bound token refreshing don't work anymore Safari and Brave are the first browser implementing those changes. Chrome will follow in 2022 (hopefully sooner) etc... Some things can be fixed, e.g. you can replace front-channel notifications with back-channel ones. Some people recommend replacing silent renew with refresh tokens. This is dangerous advice - even if your token service has implemented countermeasures. If all the security concerns around storing tokens in browsers did not worry you so far, maybe this is a good reason to consider the BFF architecture for your SPAs (if you are looking for less fancy name - it's what the BCP calls "JavaScript Applications with a back-end"). So are SPAs dead? Well - SPAs as in the UI/UX concept certainly not. SPAs as in "browser-based standalone applications that do cross-site authentication and API calls in the context of a modern identity and SSO architectures" - yes. (and they should be unless we fix some fundamental problems) my 2c. Share this: * Twitter * Facebook * Pinterest * Tumblr * Pocket * Like this: Like Loading... Related This entry was posted in OAuth, OpenID Connect. Bookmark the permalink. - Online Workshops in 2020 Major Update to IdentityModel.OidcClient - 25 Responses to SPAs are dead!? 1. [f741] Simon says: April 1, 2020 at 01:21 This also going to affect the form_post response mode in code flow right? Auth Middleware like the dotnet ones add a nonce and correlation cookie that would be considered third-party by the browser when an Identity server does the form post. I suppose we default to query now? Reply + [7568] Dominick Baier says: April 1, 2020 at 07:19 I would prefer query anyways because of a better browser navigation experience (back button). But also - the third party cookie blocking only affects non top-level windows (e.g. iframes). Reply 2. [2b2e] James Hancock says: April 1, 2020 at 15:04 I really really really wish that Browsers would step up with a standard for authentication that would allow you to call with Javascript an authenticate function and pass the OpenIdConnect Metadata URL. This would then popup a login window modally to the tab using that metadata and login, and create a full client as if you were using a native client and not a web browser. Then the browser would do refresh tokens and storage of those tokens going forward for you, and you'd have the ability to query out the Auth and Identity information using Javascript, instead of the whole thing. By doing this, it would solve the entire thing, be vastly more secure, and provide users with an excellent experience. Reply + [7568] Dominick Baier says: April 2, 2020 at 07:38 agreed. Reply 3. [37da] andsav says: April 2, 2020 at 12:22 Seems like good news since direct (without a back-end) authenticating against third-party services from a non-secure client is obviously a weak approach in many cases. Reply 4. [7568] Dominick Baier says: April 3, 2020 at 07:18 It's not about the authentication - but the session and token management Reply + [37da] andsav says: April 3, 2020 at 09:23 yes, you're right Reply 5. [e63c] Steven says: April 25, 2020 at 16:41 How about using the BFF architecture with server-side auth and refresh tokens, but having that backend send a short-lived access token to the frontend? Refresh could be handled through an API endpoint on the BFF. Yes, there is still a risk of access tokens being stolen through XSS. But this risk would be the same as we have now with the current silent refresh technique. Reply + [7568] Dominick Baier says: April 25, 2020 at 16:44 But that would mean that the client has to implement some sort of token lifetime management again? Reply o [2b2e] James Hancock says: April 25, 2020 at 16:56 No. The spa client would set it up by passing the openid config url at startup and the browser would then link it to the URL in question and do refresh tokens securely like native apps as necessary to keep login, and if not then report back with an event that the app isn't logged in anymore. JavaScript could immediately poll for login info and if got back refreshing could wait and subscribe for refresh to complete before loading so no flashing constantly. What I'm proposing is that the browser per idp setup a native secure client with best practices for openid connect automatically based on the single url for config and then JavaScript and events do the rest to pass back simple status changes allow getting info. Any site that passes that idp url for metadata shares that login and the resource permission prompt by the idp in the pop-up browser window for login by the browser controls access by that app the first time just like you get in real native apps today. This completely eliminates the refresh tokens insecurity issue on web, provides a best practices implementation as a native client and eliminates all of the weak methods for openidconnect just for browsers. Moreso, it eliminates the 3rd party cookie problem, and would fix Microsoft/Google/world+dog authentication issues with endless reprompts for nothing and edge as an example could integrate with the profile that's signed in to just work after initial prompt to allow access by the site. Even better, if this was defined in the meta tags of the root page, the browser could automatically open the site in question to the right profile. (Ie if you have 2 office 365 accounts, they can be tagged to point to the right account in the config setup and use the right profile and the right window so we don't have to manually move to a new browser or window to get the right location. It's the Holly Grail if you think about it because your app doesn't have to redirect to an auth server and then reload, it solves the refresh tokens problems and fixes all of the multisite issues of office/azure or AWS/Amazon or Google everything, and page local profile location, all in one shot. o [e63c] Steven says: April 25, 2020 at 17:00 Yes, but the advantage would be that you don't need to proxy all API requests anymore. Even with the proxy approach, you still have some of the same issues around session lifetime management. XSS would still be a very big risk, but isn't that partially mitigated by short-lived tokens? o [7568] Dominick Baier says: April 25, 2020 at 17:03 XSS is always a risk when you are running in the browser. But token exfiltration would allow the attacker to make arbitrary API calls as opposed to only via a defined interface. Token lifetime management on the server in ASP.NET Core is pretty much a solved problem - check my BFF sample. o [2b2e] James Hancock says: April 25, 2020 at 17:06 You would completely eliminate all xss issues on the login page with my approach and eliminate 3dd party cookie redirects while you're at it. The window that pops up could be hardened to prevent absolutely everything but a local form post to the same URL as the login page and block all external scripting from other browser windows entirely. And because of native client it uses refresh tokens not iframe refreshes and thus has none of those issues either. Just allow password managers to still work with special hooks. And no lifetime Management at all. The browser does the work. You just subscribe to the events it raises. o [7568] Dominick Baier says: April 25, 2020 at 17:24 You mean - if you could re-invent the web/browsers. Yes absolutely. o [2b2e] James Hancock says: April 25, 2020 at 22:18 If it could be made a standard. Which by the way, is in the interest of the browser makers (at least Google and Microsoft) both of which have a cluster f*ck going on with SSO right now. 6. [62bc] Sean Kelleher says: June 3, 2020 at 21:46 I touched on this on another comment on this site, but doesn't the fact that we won't be able to do silent renew mean that browser-based applications (even those using BFFs) will always need to ask for refresh tokens, even if we only want to access the RS while the user is present? Reply + [7568] Dominick Baier says: June 4, 2020 at 07:14 Yes. That's true. Reply o [62bc] Sean Kelleher says: June 4, 2020 at 09:43 That seems a bit awkward, as it has the potential to desensitise users to the impact of granting offline access if they always have to do it. It also bears the question of whether there's any point in asking for the permission if it's always required? I know that the OIDC spec mandates it, but I feel like the spec was likely written under the assumption that it wouldn't always be required. Perhaps requiring offline access will put greater emphasis on the ability to revoke permissions, but I think that only works if the main application exposes this functionality from the AS, and the user needs to have an awareness of the functionality. I guess it's still possible to achieve a similar outcome as silent renew by creating new windows/tabs with `prompt=none`, especially by using pop-under windows, but having windows flash open and close every couple of minutes seems like it could be very annoying and a no-go for most applications. Like others have said, browser-based handling of tokens/sessions is the ideal solution, but silent renew is what we have now, and I think that always requiring refresh tokens/offline access for client applications is a bad practice for OAuth 2. 7. [affa] dmforrester23 says: July 1, 2020 at 13:15 Hi Dominic Been researching this issue due to a Single SIgn Out requirements and it seems that SIngle Sign Out as per ID Connect spec is collateral damage from the welcome improvement of privacy provided by blocking 3rd party cookies? Is this your understanding and do you know of any official articles from Microsoft / Identity Server on the impact and mitigation of this change when using their product and implementing single sign out? Reply + [7568] Dominick Baier says: July 1, 2020 at 15:45 Well - back-channel notifications is the only technique that will reliably work in the future across domain boundaries. Reply 8. [2b2e] James Hancock says: July 1, 2020 at 19:43 One has to believe that the better solution to this is for the browser manufacturers to put in full Native client OpenIdConnect support that is per website with a javascript kickoff. It would popup a window, use full native authenticaiton with client id and client secret and do referesh tokens as well based on a login() with a discoveryUrl, and clientId (if already logged in would return immediately). Then it would with have a notification event that would fire to get the latest authToken, or it could be set to intercept fetch by default and add the bearer token securely. Everything would be stored encrypted within the built in client. New authentication methods could be added as needed but the mechanism would stay the same. This to me is the only real solution to the problem at hand. Everything else is a hack. And this solution ensures that we don't have SPAs reloading after login too. Reply 9. [0aeb] John says: August 26, 2020 at 00:22 We have fully deployed an application ecosystem using Identity Server 4 to provide single sign on between two SPAs, a mobile app and also securing the API. Now we are being tasked with fixing the 3rd party cookie blocking issue by the client. Many of the QA testers are using Macs with Safari and thus have 3rd party cookies blocked by default. We are using sub-domains for all of the different apps... api.mydomain.com, sso.mydomain.com, spa1.mydomain.com, etc. Is implementing a reverse proxy the least painful way to address this issue right now? So essentially api.mydomain.com becomes mydomain.com/api and so forth. Reply + [7568] Dominick Baier says: August 31, 2020 at 16:14 Interesting. I was under the impression that same sites are not considered "third party". Are you sure that this is the problem? Reply 10. [2007] Sean says: December 4, 2020 at 17:28 Starting a green field project thinking of doing a mini-SPA setup with aspnet core BFF and ID Server. Would it be totally insecure to utilize refresh tokens in the back-end, then update the SPA with new auth tokens via a secure websocket? We're very new yet to ID server and openidconnect in general, are there any recommended approaches by chance for such a setup? Any feedback/ advice is much appreciated. Thanks. Reply + [7568] Dominick Baier says: December 4, 2020 at 20:59 That sounds like storing tokens in the browser. That's what you want to avoid. Reply Leave a Reply Cancel reply Enter your comment here... [ ] Fill in your details below or click an icon to log in: * * * * Gravatar Email (required) (Address never made public) [ ] Name (required) [ ] Website [ ] WordPress.com Logo You are commenting using your WordPress.com account. ( Log Out / Change ) Google photo You are commenting using your Google account. ( Log Out / Change ) Twitter picture You are commenting using your Twitter account. ( Log Out / Change ) Facebook photo You are commenting using your Facebook account. ( Log Out / Change ) Cancel Connecting to %s [ ] Notify me of new comments via email. [ ] Notify me of new posts via email. [Post Comment] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] * Search for: [ ] [Search] * Recent Posts + The Future of IdentityServer + Flexible Access Token Validation in ASP.NET Core + Refresh Tokens in IdentityServer4 v4 + Announcing IdentityServer4 v4.0 + Resource Access in IdentityServer4 v4 and going forward * Categories + .NET Security (95) + ASP.NET (163) + ASP.NET Core (27) + AuthorizationServer (33) + Azure (29) + Conferences & Training (40) + IdentityModel (347) + IdentityServer (205) + Katana (46) + OAuth (163) + OpenID Connect (94) + OWIN (45) + Photography (14) + PolicyServer (3) + Resources (1) + Uncategorized (624) + WCF (109) + WebAPI (223) * Tweets + That's often the start of a good story "Hence, GitHub created a custom authentication flow" I am glad we have Ope... twitter.com/i/web/status/1... 1 day ago + Next week we are running our High Security OAuth Workshop ndcworkshops.com/slot/high-secu... Join us for a full day of secu... twitter.com/i/web/status/1... 1 day ago Follow @leastprivilege * Feed RSS Feed RSS - Posts RSS Feed RSS - Comments * Archives + October 2020 + July 2020 + June 2020 + May 2020 + April 2020 + March 2020 + February 2020 + January 2020 + September 2019 + August 2019 + July 2019 + June 2019 + April 2019 + February 2019 + January 2019 + December 2018 + July 2018 + June 2018 + May 2018 + February 2018 + January 2018 + December 2017 + November 2017 + October 2017 + August 2017 + July 2017 + May 2017 + April 2017 + March 2017 + February 2017 + January 2017 + December 2016 + October 2016 + September 2016 + August 2016 + July 2016 + June 2016 + May 2016 + February 2016 + January 2016 + December 2015 + November 2015 + October 2015 + September 2015 + July 2015 + June 2015 + May 2015 + April 2015 + March 2015 + February 2015 + January 2015 + December 2014 + November 2014 + October 2014 + September 2014 + August 2014 + July 2014 + June 2014 + May 2014 + April 2014 + March 2014 + February 2014 + January 2014 + December 2013 + November 2013 + October 2013 + September 2013 + August 2013 + July 2013 + June 2013 + May 2013 + April 2013 + March 2013 + February 2013 + January 2013 + December 2012 + November 2012 + October 2012 + September 2012 + August 2012 + July 2012 + June 2012 + May 2012 + April 2012 + March 2012 + February 2012 + January 2012 + December 2011 + November 2011 + October 2011 + September 2011 + July 2011 + June 2011 + May 2011 + April 2011 + March 2011 + February 2011 + January 2011 + December 2010 + November 2010 + October 2010 + September 2010 + August 2010 + July 2010 + June 2010 + May 2010 + April 2010 + March 2010 + February 2010 + December 2009 + November 2009 + October 2009 + September 2009 + August 2009 + July 2009 + June 2009 + May 2009 + April 2009 + March 2009 + February 2009 + January 2009 + December 2008 + November 2008 + October 2008 + September 2008 + August 2008 + July 2008 + June 2008 + May 2008 + April 2008 + March 2008 + February 2008 + January 2008 + December 2007 + November 2007 + October 2007 + September 2007 + August 2007 + July 2007 + June 2007 + May 2007 + April 2007 + March 2007 + February 2007 + January 2007 + December 2006 + November 2006 + October 2006 + September 2006 + August 2006 + July 2006 + June 2006 + May 2006 + April 2006 + March 2006 + February 2006 + January 2006 + December 2005 + November 2005 + October 2005 + September 2005 + August 2005 + July 2005 + June 2005 + May 2005 + April 2005 + March 2005 + February 2005 + January 2005 + December 2004 + November 2004 + October 2004 + September 2004 + August 2004 + July 2004 + June 2004 + May 2004 leastprivilege.com Blog at WordPress.com. %d bloggers like this: [b]