Take the community feedback survey now.

Jafet Valdez
Sep 20, 2018
  10500
(2 votes)

Curing your Redirect woes when using ASP.NET Identity and UISignInManager.SignIn()

Hello World.

In this post I'll show you how to modify UISignInManager so that it does not fully rely on the ReturnUrl query parameter for redirects, enabling us to use whatever redirection logic we may desire and/or require!

The context

I recently ran into a thread here on World where a fellow developer had some issues with users being redirected to the sites' root page (”/”) after signing them in through a call to UISignInManager.SignIn().

The intent was to redirect the users to a specific Url after signing them in. Sounds reasonable.

But the issue with redirecting to another url after calling SignIn() is that the SignIn method already sets a redirect location on the response, which means that you can try to redirect as much as you want afterwards. The user will still be redirected to whatever the SignIn() method decided to redirect to.

And what does the SignIn()-method decide to redirect to? The ReturnUrl in the query parameters (for example ”/Login?ReturnUrl=/ALockedPage”).

This is fine in most cases where you, for example, get redirected to the login page for trying to access a page where users need to be authenticated. But what happens if you don’t have a ReturnUrl query paremeter set? Well it will simply redirect to ”/” – in other words, the sites’ root page. This may not be what you want in all cases, especially if you have a custom login page with custom redirection logic.

Note: This SignIn() redirect also overrides redirects that you do in the OnResponseSignIn Action in your OWIN configuration (a.k.a. Startup.cs).

So how do we solve this?

Well, we create our own UISignInManager of course!

In this approach we'll modify the SignIn method so that it doesn't automatically redirect to sites' root page if we do not have a ReturnUrl set.

    public class MyApplicationUISignInManager<TUser> : ApplicationUISignInManager<TUser> where TUser : IdentityUser, IUIUser, new()
    {

        protected ApplicationSignInManager<TUser> _signInManager;

        public MyApplicationUISignInManager(ServiceAccessor<ApplicationSignInManager<TUser>> signInManager) : base(signInManager)
        {
            _signInManager = signInManager();
        }

        public override bool SignIn(string providerName, string userName, string password)
        {

            if (HasReturnUrl()) // Use the default implementation if we have a ReturnUrl set
                return base.SignIn(providerName, userName, password);

            return _signInManager.SignIn(userName, password, null);
        }

        private bool HasReturnUrl()
        {
            return HttpContext.Current?.Request.QueryString?.Get("ReturnUrl") != null;   
        }


        /// <summary>
        /// Creates an instance of MyApplicationUISignInManager. Mainly for setting up the IoC Container.
        /// </summary>
        /// <param name="options"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        public new static UISignInManager Create(IdentityFactoryOptions<UISignInManager> options, IOwinContext context)
        {
            return new MyApplicationUISignInManager<TUser>(context.Get<ApplicationSignInManager<TUser>>);
        }
    }

In this case, we only want to modify what happens if we do not have a ReturnUrl. So if we have a query parameter named ReturnUrl, we just use the standard UISignInManager code to handle that case. Otherwise we sign the user in ourselves without specifying a return url.

Now we need to setup our IoC to use our new UISignInManager.

This can be done in your Startup.cs file, just after you call the built in AddCmsAspNetIdentity() where all the default Managers and Providers are setup.

    // Example Startup.cs class
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.AddCmsAspNetIdentity<ApplicationUser>();

            app.CreatePerOwinContext<UISignInManager>(MyApplicationUISignInManager<ApplicationUser>.Create); // <-- Add this line after calling app.AddCmsAspNetIdentity

            app.UseCookieAuthentication(new CookieAuthenticationOptions
            {
                AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
                LoginPath = new PathString("/Util/Login.aspx"),
                Provider = new CookieAuthenticationProvider
                {
                    OnValidateIdentity =
                        SecurityStampValidator
                            .OnValidateIdentity<ApplicationUserManager<User>, User>(
                                TimeSpan.FromMinutes(30),
                                (manager, user) => manager.GenerateUserIdentityAsync(user)),
                    OnApplyRedirect = context => context.Response.Redirect(context.RedirectUri),
                    OnResponseSignOut = context => context.Response.Redirect("/ByeWorld"),
                    OnResponseSignIn = context => context.Response.Redirect("/HelloWorld") // This now works too! Yay!
                }
            });
        }
    }

Note: In my example I call a static Create method that lives in my own implementation of UISignInManager, this is so that it’s done in a similar fashion to how the others defaults are setup in case you set them up manually instead of calling AddCmsAspNetIdentity().

Now you’re set and can start redirecting to whatever you want, either through the OnResponseSignIn action or manually after signing in users through UISignInManager.SignIn()! 😊

Sep 20, 2018

Comments

Please login to comment.
Latest blogs
Optimizely Opal : Reimagining A Utility Sector Use Case

  Introduction Customer engagement through timely and personalized push notifications plays a crucial role in todays Digital First landscape. In th...

Ratish | Sep 12, 2025 |

A day in the life of an Optimizely OMVP - AEO & GEO: The Future of Digital Visibility with Optimizely

The way people discover content online is undergoing a seismic shift. Traditional SEO is no longer enough. With AI-powered tools like ChatGPT,...

Graham Carr | Sep 12, 2025

Building Optimizely OCP Apps Faster with AI and Coding Assistants

Developing Optimizely Connect Platform (OCP) apps can be a rewarding but complex process—especially when integrating with external APIs. Over the...

Pawel Zieba | Sep 11, 2025

New Opal Certifications Are Live and Free!

We’ve got some exciting news to share: two brand-new Opal certifications are now available and they’re completely free. Whether you’re already...

Satata Satez | Sep 10, 2025