How does OAuth with OWIN works in MVC5?
Asked Answered
B

1

8

I am trying to understand how OAuth work, but it feels like one big magic show, and I don't like that.

I have created a new MVC5 project and enabled facebook authentication. This all just works fine, however, I am trying to understand how this works.

Here is the part where I get lost. Imagine a user wants to log in for the very first time. This method is the executed:

    public async Task<ActionResult> ExternalLoginCallback(string returnUrl)
    {
        var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync();
        if (loginInfo == null)
        {
            return RedirectToAction("Login");
        }

        // Sign in the user with this external login provider if the user already has a login
        var result = await SignInManager.ExternalSignInAsync(loginInfo, isPersistent: false);
        switch (result)
        {
            case SignInStatus.Success:
                return RedirectToLocal(returnUrl);
            case SignInStatus.LockedOut:
                return View("Lockout");
            case SignInStatus.RequiresVerification:
                return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = false });
            case SignInStatus.Failure:
            default:
                // If the user does not have an account, then prompt the user to create an account
                ViewBag.ReturnUrl = returnUrl;
                ViewBag.LoginProvider = loginInfo.Login.LoginProvider;
                return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { Email = loginInfo.Email });
        }
    }

This code shows the FB login page and FB will take care of the credentials. This all works fine. But then, this line is executed: var result = await SignInManager.ExternalSignInAsync(loginInfo, isPersistent: false);. I can see in loginInfo that a name is set, but the result variabel is set to Failure. Why is that? The user has just been authenticated by FB, so why is the value false?

But then, for my feeling it gets weirder. When I continue to run the sample application, it asks for me to enter an e-mail address. I enter an e-mail address and voila, I am logged in. Since I am exploring this whole login thing, I log off and I want to log in again. So, I log off and immediatly log in again using FB. And here is where I bang my head against the wall. When the code hits this line again: var result = await SignInManager.ExternalSignInAsync(loginInfo, isPersistent: false); the result is set to true!!

Could someone please explain to me what's all going on here??

Basrelief answered 3/6, 2015 at 18:18 Comment(0)
C
5

When you use external login the SignInManager validates the user credentials with the external party (in this case Facebook). If the external party has successfully validated the credentials the SignInManager checks if an user record is present. Since this is you're first login there isn't any available user record. This part takes care of that:

case SignInStatus.Failure:
        default:
            // If the user does not have an account, then prompt the user to create an account
            ViewBag.ReturnUrl = returnUrl;
            ViewBag.LoginProvider = loginInfo.Login.LoginProvider;
            return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { Email = loginInfo.Email });

This allows you to use another email address. Mostly common is to use the same email address!

Some samples: http://www.asp.net/mvc/overview/security/create-an-aspnet-mvc-5-app-with-facebook-and-google-oauth2-and-openid-sign-on.

Collum answered 3/6, 2015 at 18:49 Comment(3)
Thanks. Where can I find the part where the SignInManager checks if a record is present? This feels a kind of magical.Basrelief
Found it on this website: symbolsource.org/MyGet/Metadata/aspnetwebstacknightly/Project/….Collum
Yes, after looking at the source, I believe SignInStatus.Failure is named just to confuse. In calling SignInManager.ExternalSignInAsync(), I believe it can only be returned for a user not found. It can be returned for other types failures in other calls.Turgeon

© 2022 - 2024 — McMap. All rights reserved.