locked
Web Api 2 RegesterExternal returning Internal Server Error RRS feed

  • Question

  • User1498905560 posted

    I am having trouble implementing external logins in Web Api 2.

    I have tried to implement this using the default templates in VS 2013 Community and VS 2015 CTP.  The only change I make is uncomment the google auth code in Startup.Auth and enter ClientId and ClientSecret.

    Step 1

    I call GET api/Account/ExternalLogins?returnUrl=%2F&generateState=true and I retrieve the external login url for google.

    Step 2

    I copy the url an call it and I'm redirected to google and I login.  Google redirects back to my site with the external token.

    Step 3

    I call Post to api/Account/UserInfo with the external token received from google in the header.

    Result = {"Email":"MyName","hasRegistered":false,"loginProvider":"Google"}

    All fine up until now.

    Because hasRegistered = false as we can see above I need to call

    POST api/Account/RegisterExternal to register a local account.

    I pass the external token in the header and also pass the email address in the body.  Within the RegisterExternal method there is a call to an async method:

    var info = await Authentication.GetExternalLoginInfoAsync(); - This always returns null.

    I have enabled the google api in the google developer console.

    Is this a bug in the templates or am I missing something?

    Can somebody try replicate this with the default Web Api temple and see if it works for you.

    Thanks

    Thursday, June 4, 2015 8:20 AM

Answers

  • User1498905560 posted

    Hi

    Yes I got it working in the end.

    In the RegisterExternal method it was calling:

    var info = await AuthenticationManager.GetExternalLoginInfoAsync()

    Within the GetExternalLoginInfoAsync method it calls another method:

    var result = await Authentication.AuthenticationAsync(DefaultAuthenticationTypes.ExternalCookie);

    The DefaultAuthenticationTypes.ExternalCookie parameter is where the problem lies.  I had to create my own method and pass DefaultAuthenticationTypes.ExternalBearer instead like so:

    private async Task<ExternalLoginInfo> AuthenticationManager_GetExternalLoginInfoAsync_WithExternalBearer()
            {
                ExternalLoginInfo loginInfo = null;
    
                var result = await Authentication.AuthenticateAsync(DefaultAuthenticationTypes.ExternalBearer);
    
                if (result != null && result.Identity != null)
                {
                    var idClaim = result.Identity.FindFirst(ClaimTypes.NameIdentifier);
                    if (idClaim != null)
                    {
                        loginInfo = new ExternalLoginInfo()
                        {
                            DefaultUserName = result.Identity.Name == null ? "" : result.Identity.Name.Replace(" ", ""),
                            Login = new UserLoginInfo(idClaim.Issuer, idClaim.Value)
                        };
                    }
                }
                return loginInfo;
            }

    Add this method to your controller and then in the RegisterExternal method change to call your new method like so:

    var info = await AuthenticationManager_GetExternalLoginAsync_WithExternalBearer();

    Hope that helps.

    Paul

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, July 6, 2015 5:41 AM

All replies

  • User1644755831 posted

    Hello Paul3654,

    Using the information from following Articles on how to do external login with google OAuth2 I was able to make it working with New SPA default Template.

    http://www.asp.net/web-api/overview/security/external-authentication-services#GOOGLE (How to create SPA Template) (this one uses Old oauth authentication which is deprecated)

    http://www.asp.net/mvc/overview/security/create-an-aspnet-mvc-5-app-with-facebook-and-google-oauth2-and-openid-sign-on#1st  (see this for how to do Oauth2 authentication)

    1. Created Single Page Application Template.

    2. followed the second article and created secret and client id

    Client ID: 973949399036-n01vh6n22851rfjc8lsdgc7h27rerq52.apps.googleusercontent.com
    
     
    Email address: 973949399036-n01vh6n22851rfjc8lsdgc7h27rerq52@developer.gserviceaccount.com
     
     
    Client secret : NyQ727vy7SoZk_CwStTdV7SM
     
     
    Redirect URIs : https://localhost:64971/signin-google 
        
     
    JavaScript origins: https://localhost:64971/
    

    3. I published my website to local IIS with SSL Enabled like described and set Redirect URIs and JavaScript Origin Accordingly.

    4. Enabled Google+ API

    5. And then run it and was able to get it working.

    Sample Demo (2054224.zip) 

    Hope this helps.

    With Regards,

    Krunal Parekh

    Monday, June 8, 2015 2:20 AM
  • User1498905560 posted

    Hi Krunal

    Thanks for having a look at my problem.  I have come across the posts that you have linked and can see that it works if you call the 'Register' method from the Register page.  My app is just a web api app (no register/login page). 

    Instead of calling the 'Register' method in the account controller, call the 'RegisterExternal' method and you will see that it doesn't work.

    Thanks

    Monday, June 8, 2015 5:10 AM
  • User1644755831 posted

    Hello Paul3654,

    Thanks for having a look at my problem.  I have come across the posts that you have linked and can see that it works if you call the 'Register' method from the Register page.  My app is just a web api app (no register/login page). 

    Instead of calling the 'Register' method in the account controller, call the 'RegisterExternal' method and you will see that it doesn't work.

    Can you elaborate on this I am afraid I don't see any Register External method in my application. Are you trying to register when trying Oauth2 authentication?

    With Regards,
    Krunal Parekh

    Monday, June 8, 2015 5:39 AM
  • User1498905560 posted

    Hi Krunal

    If you create a new ASP.Net project in VS 2013 or 2015 and choose the Web Api template with individual accounts for security(you won't have a login or register pages), you will see that you will now have methods for connecting to the web api from various clients.  If you want to connect from a native mobile app for example you will have to call the RegisterExternal method to create a local account.

    Here is a link to SO outliningthe process.

    http://stackoverflow.com/questions/21065648/asp-net-web-api-2-how-to-login-with-external-authentication-services

    Hope I'm explaining correctly.

    Thanks

    Monday, June 8, 2015 5:58 AM
  • User915148580 posted

    Paul3654

    Were you able to find a solution to that? I am also stuck with that?

    Monday, July 6, 2015 1:33 AM
  • User1498905560 posted

    Hi

    Yes I got it working in the end.

    In the RegisterExternal method it was calling:

    var info = await AuthenticationManager.GetExternalLoginInfoAsync()

    Within the GetExternalLoginInfoAsync method it calls another method:

    var result = await Authentication.AuthenticationAsync(DefaultAuthenticationTypes.ExternalCookie);

    The DefaultAuthenticationTypes.ExternalCookie parameter is where the problem lies.  I had to create my own method and pass DefaultAuthenticationTypes.ExternalBearer instead like so:

    private async Task<ExternalLoginInfo> AuthenticationManager_GetExternalLoginInfoAsync_WithExternalBearer()
            {
                ExternalLoginInfo loginInfo = null;
    
                var result = await Authentication.AuthenticateAsync(DefaultAuthenticationTypes.ExternalBearer);
    
                if (result != null && result.Identity != null)
                {
                    var idClaim = result.Identity.FindFirst(ClaimTypes.NameIdentifier);
                    if (idClaim != null)
                    {
                        loginInfo = new ExternalLoginInfo()
                        {
                            DefaultUserName = result.Identity.Name == null ? "" : result.Identity.Name.Replace(" ", ""),
                            Login = new UserLoginInfo(idClaim.Issuer, idClaim.Value)
                        };
                    }
                }
                return loginInfo;
            }

    Add this method to your controller and then in the RegisterExternal method change to call your new method like so:

    var info = await AuthenticationManager_GetExternalLoginAsync_WithExternalBearer();

    Hope that helps.

    Paul

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, July 6, 2015 5:41 AM
  • User915148580 posted

    This worked for me. Please mark your solution as accepted, so that others can benefit from it.

    Monday, July 6, 2015 2:15 PM