This is probably the most specific post I’ve written in a long time, but given how long I let it fester, and how much debugging it took to figure out, I figure it’s worth saving someone the time. Last fall you might recall that I did a little bit of reverse engineering, and some cutting and pasting of source code, to use the OWIN-based external authentication stuff, decoupling it from ASP.NET Identity. This was a pretty exciting win for me because I was completely not interested in using yet another auth system in POP Forums, when the one I had was already pretty simple and embedded in some of my own projects.
When I integrated it into CoasterBuzz, it worked like a champ right away. Then I went to add it to another project I was working on, and it didn’t work. For reasons I can’t explain, the new project was forcing a redirect to the forms auth login page (which defaults to /login.aspx), and putting a referrer in the query string to /Forums/Authorization/ExternalLoginCallback, which was the intended callback URL. I was completely stumped, because obviously the forum assemblies were exactly the same on CoasterBuzz and the new project. I first assumed that it was some kind of routing problem, or maybe an ordering problem in the OWIN and other app startup pieces. I got exactly nowhere going down this road.
With fresh eyes, having not gone back to it in several months, I started to wonder where exactly the redirect was occurring. The MVC pipeline is a weird mix on top of ASP.NET, and while FormsAuthentication is certainly a construct of the ASP.NET days, it’s silly easy to use it in MVC. Instead of using HttpModules for plumbing in WebForms, I use action filters in MVC. One of the super convenient things in POP Forums is that you can set that filter to apply to every action in your app, and then opt out certain methods with a different attribute (think actions that return data like images). Thinking about all of that, I still assumed it was code specific to the external login magic.
What I could see is that execution got as far as the ExternalLogin action in the Authorization controller. That created a ChallengeResult instance, which I “borrowed” from the original source. What goes on beyond that I couldn’t tell you, because it’s in one of the Owin libraries, and I wasn’t brave enough to go digging there. All I knew for sure is that this was the last code to execute unless I ripped out the authorization element from my web.config, and that led me to believe this was ASP.NET getting in the way.
After much searching on various keywords like “formsauth redirect,” “override,” “prevent” and finally “suppress,” I found that HttpResponse gained a new property in v4.5 called SuppressFormsAuthenticationRedirect. It does exactly what it sounds like it does, and this fixed my problem. Setting this one property in the context of that “borrowed” ChallengeResult did the trick. The new project will bounce you through to Google or Facebook or whatever to login, as it does on a “naked” instance of the forum app. Life is good.
Not one of my proudest debugging moments, but I’ll sleep better tonight!