4

I'm trying to add LinkedIn authentication to my ASP.NET Core 2.0 app but getting the following error:

No authentication handler is configured to handle the scheme: LinkedIn

Here's how I add LinkedIn/OAuth authentication in the ConfigureServices in Startup.cs:

services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
   .AddCookie("internal_cookie", options => {
         options.AccessDeniedPath = "/Account/Forbidden/";
         options.LoginPath = "/Account/Login";
    })
   .AddCookie("external_cookie")
   .AddOAuth("LinkedIn", options => {

         options.SignInScheme = "external_cookie";
         options.ClientId = "1234567890";
         options.ClientSecret = "1234567890";
         options.CallbackPath = "/linkedin-callback";

         options.AuthorizationEndpoint = "https://www.linkedin.com/oauth/v2/authorization";
         options.TokenEndpoint = "https://www.linkedin.com/oauth/v2/accessToken";
         options.UserInformationEndpoint = "https://api.linkedin.com/v1/people/~:(id,first-name,last-name,email-address,picture-url,picture-urls::(original))";

         options.Scope.Add("r_basicprofile");
         options.Scope.Add("r_emailaddress");

         options.Events = new OAuthEvents
         {
             OnCreatingTicket = OnCreatingTicketLinkedInCallBack,
             OnTicketReceived = OnTicketReceivedCallback
         };
    })
    .AddFacebook(options =>
    {
          options.AppId = "1234567980";
          options.AppSecret = "1234567890";
          options.Events = new OAuthEvents
          {
             OnCreatingTicket = OnCreatingTicketFacebookCallback,
             OnTicketReceived = OnTicketReceivedCallback
          };
     })
     .AddGoogle(options =>
     {
           options.ClientId = "1234567890";
           options.ClientSecret = "1234567890";
           options.CallbackPath = "/google-callback";
           options.Events = new OAuthEvents
           {
              OnCreatingTicket = OnCreatingTicketGoogleCallback,
              OnTicketReceived = OnTicketReceivedCallback
           };
});

Where's my error?

UPDATE: After making the corrections suggested, I'm now getting the following error:

No IAuthenticationSignInHandler is configured to handle sign in for the scheme: social_login

Sam
  • 26,817
  • 58
  • 206
  • 383

1 Answers1

5

You mixed up the authentication scheme associated with your custom LinkedIn handler registration with the sign-in scheme that OAuthHandler will ultimately call to persist the identity (typically a cookie handler instance).

Fix your registration to specify LinkedIn as the scheme and social_login as the sign-in scheme (assuming your cookie handler is indeed named social_login), and it should work:

services.AddAuthentication()
    .AddCookie("social_login")
    .AddOAuth("LinkedIn", options =>
    {
        options.SignInScheme = "social_login";

        // ...
    });

Note: you can remove the SignInScheme assignation if social_login is the default sign-in scheme (i.e if you call services.AddAuthentication("social_login") or services.AddAuthentication(options => options.DefaultSignInScheme = "social_login"):

services.AddAuthentication("social_login")
    .AddCookie("social_login")
    .AddOAuth("LinkedIn", options =>
    {
        // ...
    });
Kévin Chalet
  • 39,509
  • 7
  • 121
  • 131
  • I just posted an update to my original post. I'm actually glad this has come up. I would like to use different schemes so that my internally produced cookie will have a different "name" than the ones I get from social auth providers. I'm just not sure how to handle the new error I'm getting. – Sam Aug 19 '17 at 23:27
  • Is your cookie handler instance named `social_login`? Posting the whole code would help. – Kévin Chalet Aug 19 '17 at 23:27
  • Updated the whole code section in the original post to show you my entire authentication config section. – Sam Aug 19 '17 at 23:35
  • Replace `social_login` by `CookieAuthenticationDefaults.AuthenticationScheme` in my code or update yours to use `social_login` for the cookie handler name. – Kévin Chalet Aug 19 '17 at 23:37
  • Would that mean both my internal cookies and the ones I get from FB/Google/LinkedIn will have the same name? I think it's a good idea to have them different so that only the cookies I create internally will be accepted for authenticated users. Or am I wrong about this? – Sam Aug 19 '17 at 23:38
  • 1
    I really am not an expert on this but if I understand this correctly, I do get a cookie from social providers. I've had problems in the past where my app accepted those cookies and considered the user authenticated. What I do is that once I get proper response from social providers, I kill that cookie and create a new one with all the user info I need and use that cookie as my "legit" cookie. Makes sense? – Sam Aug 19 '17 at 23:41
  • 1
    You don't exactly "get" a cookie from the external providers, but the OAuth2 handler indeed creates one for you by asking the cookie handler represented by `SignInScheme` to do it when your users reach the callback path with the OAuth2 authorization code. Having two separate cookies is possible (it's the approach used by ASP.NET Core Identity). For that, just spawn another cookie handler instance: `.AddCookie("internal_cookie").AddCookie("external_cookie")`. – Kévin Chalet Aug 19 '17 at 23:44
  • I get the idea now but my implementation is still not working. I just updated the code section in original post. I'm now getting `No authenticationScheme was specified, and there was no DefaultChallengeScheme found` error. – Sam Aug 19 '17 at 23:54
  • So, in my code, I'm trying to use the `CookieAuthenticationDefaults.AuthenticationScheme` for my internal authentication and I'm trying to "name" the external one. – Sam Aug 19 '17 at 23:56
  • Change `CookieAuthenticationDefaults.AuthenticationScheme` to `internal_cookie` as your cookie handler no longer uses the default name. – Kévin Chalet Aug 19 '17 at 23:57
  • I think I got it now but looks like I need to do one more thing. I was getting user data from social providers with `var user = HttpContext.User;` which no longer gives me any data. I need to somehow specify the name of the cookie from OAuth2, correct? – Sam Aug 20 '17 at 00:03
  • 1
    Right. Use `HttpContext.AuthenticateAsync("external_cookie")` to retrieve the claims stored in the external cookie. – Kévin Chalet Aug 20 '17 at 00:04
  • Excellent! I can't thank you enough. You've been super super helpful. – Sam Aug 20 '17 at 00:04
  • @Sam my pleasure :) – Kévin Chalet Aug 20 '17 at 00:07