ASP.NET Web API 2: How do I log in with external authentication services?

43,080

Solution 1

I had the same problem today and found the following solution:

At first get all available providers

GET /api/Account/ExternalLogins?returnUrl=%2F&generateState=true

The response message is a list in json format

[{"name":"Facebook",
  "url":"/api/Account/ExternalLogin?provider=Facebook&response_type=token&client_id=self&redirect_uri=http%3A%2F%2Flocalhost%3A15359%2F&state=QotufgXRptkAfJvcthIOWBnGZydgVkZWsx8YrQepeDk1",
  "state":"QotufgXRptkAfJvcthIOWBnGZydgVkZWsx8YrQepeDk1"}]

Now send a GET request to the url of the provider you want to use. You will be redirected to the login page of the external provider. Fill in your credentials and the you will be redirected back to your site. Now parse the access_token from the url.

http://localhost:15359/#access_token=[..]&token_type=bearer&expires_in=[..]&state=QotufgXRptkAfJvcthIOWBnGZydgVkZWsx8YrQepeDk1

If the user already has a local account, the .AspNet.Cookies cookie is set and you are done. If not, only the .AspNet.ExternalCookie cookie is set and you have to register a local account.

There is an api to find out if the user is registered:

GET /api/Account/UserInfo

The response is

{"userName":"xxx","hasRegistered":false,"loginProvider":"Facebook"}

To create a local account for the user, call

POST /api/Account/RegisterExternal
Authorization: Bearer VPcd1RQ4X... (access_token from url)
Content-Type: application/json
{"UserName":"myusername"}

Now send the same request with the provider url as before

GET /api/Account/ExternalLogin?provider=Facebook&response_type=token&client_id=self&redirect_uri=http%3A%2F%2Flocalhost%3A15359%2F&state=QotufgXRptkAfJvcthIOWBnGZydgVkZWsx8YrQepeDk1

But this time the user already has an account and gets authenticated. You can verify this by calling /api/Account/UserInfo again.

Now extract the access_token from the url. You have to add the Authorization: Bearer [access_token] header to every request you make.

Solution 2

I found another post showing pretty details how this external authentication works. The client is WPF and server uses ASP.NET Identity.

Share:
43,080
acor3
Author by

acor3

i'm NaN... i'm a Fr33 Man... ahahhahaha

Updated on July 09, 2022

Comments

  • acor3
    acor3 almost 2 years

    According to this post http://www.asp.net/web-api/overview/security/external-authentication-services... I'm able to log in with a local authentication service (with the new ASP.NET identity framework)

    but I can't find a walkthrough to properly call (from a mobile app or Postman) the default web API generated in the Visual Studio 2013 SPA template.

    Can anyone help me?

  • acor3
    acor3 over 10 years
    my main problem is that my client in not a web application but a native mobile application (andoird app or IOS app)
  • Joe the Coder
    Joe the Coder over 10 years
    @acor3 - it's the same process no matter what platform you're using. In the case of native mobile apps, you would open up a web view within your app (UIWebView on iPhone, WebView on Android), send the user to the url of the provider they chose, allow them to log in, and have the redirect url go to a page in your api that contains a magic token. Your app would then look in the web view for that token, and once it's found, it would grab the bearer/access tokens from it, then you can use it in your native HTTP GET/POST calls.
  • Bartosz
    Bartosz over 10 years
    @berhir - thanks for your answer, I found it really useful with getting my head around Web API 2 security. My scenario is slightly different though. I call API from another MVC application. So where you say 'you will be redirected back to your site. Now parse the access_token from the url' how would you approach it in my case?
  • acor3
    acor3 over 10 years
    hi all.. check this question. stackoverflow.com/questions/21092723/…
  • Alexey Strakh
    Alexey Strakh about 10 years
    Thank you for the detailed guide! What if I already have a token and would like to authenticate user against web api using it. I got this token by internal iOS SDK api, which allows you to get the token without opening a webview.
  • berhir
    berhir about 10 years
    I have no experience with iOS so I don't know what API you have there. But if you already got a token from your web api application, you just need to add it to the header of every http request as mentioned in my answer. If this doesn't help you, please give some more details on what you want to do.
  • razeth01
    razeth01 almost 10 years
    @berhir I successfully followed your example and its working fine till the point after I register the user external. The when I want to log in again with a with the external user(local saved now) the access token does not get attached to the url. The browser stays at the same ExternalLogin page. Could the problem be that I'm using the applicationUser override and not the IdentityUser.
  • NVM
    NVM over 9 years
    I believe 'Now send a GET request to the url of the provider you want to use.' should actually be 'Redirect to to the url of the provider you want to use." and also "Now send the same request with the provider url as before" should be "Now again Now send the same request with the provider url as before."
  • Richa
    Richa about 9 years
    I am working on a project with titanium SDK and using above steps for facebook login. All works fine in iOS but on android webview it's getting fail at step “If user is not already registered, only the .AspNet.ExternalCookie cookie is set and you have to register a local account." , I am not getting '.AspNet.ExternalCookie' and therefore can not succeed further. If user is already registered all works well even on android. Did anyone faced this issue ? I've been stuck in this issue since a long time. Any help would be really appreciated.
  • berhir
    berhir about 9 years
    @Richa Unfortunately I'm not familiar with the Android WebView, but maybe the answers to this question can help: stackoverflow.com/questions/2566485/…
  • Alberto Montellano
    Alberto Montellano about 9 years
    How do you extract the access token from url?
  • BrunoRamalho
    BrunoRamalho over 8 years
    could you explain how to get the Facebook access token after the login?
  • berhir
    berhir over 8 years
    @BrunoRamalho To get the access token, you need to parse it from the url. If you use C# for example, you can use the Uri.Fragment property.
  • berhir
    berhir over 8 years
    @BrunoRamalho Sorry, I made a mistake. Here is an example: In C# you can use the Uri class and HttpUtility.ParseQueryString method. Uri uri= new Uri("http://localhost:15359/#access_token=[..]&token_type=be‌​arer&expires_in=[..]‌​&state=QotufgXRptkAf‌​JvcthIOWBnGZydgVkZWs‌​x8YrQepeDk1"); string access_token = HttpUtility.ParseQueryString(uri.Query).Get("access_token");
  • BrunoRamalho
    BrunoRamalho over 8 years
    yes, is more or less this, however this is helping me solving the problem stackoverflow.com/questions/32508261/…
  • Warren
    Warren over 8 years
    Does anyone have any idea how to set the returnUrl to an angular view, cuz I'm really looking for a way to make this work? '/api/account/externalLogins?returnUrl='+ encodeURIComponent('/user#/register-external') +'
  • berhir
    berhir over 8 years
    @WarrenDodsworth It's not possible to add a hash property to the return url. But you can add the return url to the state parameter and then parse it from there when the call comes back from the authorization server. Here is a working sample: github.com/manfredsteyer/angular-oauth-oidc/blob/master/app/‌​… It's a hack but I don't know about a better solution.
  • Nithish Inpursuit Ofhappiness
    Nithish Inpursuit Ofhappiness over 8 years
    @berhir I'm making a GET request to the url of the provider I want to use - Microsoft Account. I am redirected to the login page and I'm able to get the access token from the URL. However when I try to use this against the api/Account/UserIdentity, I'm still unauthorized. I tried making this action method as [AlowAnonymous] and the Email attribute of the returned user was null and so was the AuthenticationProvider attribute of the JSON object. More weirdly, the IsRegistered attribute is already returning true. Any pointers??
  • Hithesh
    Hithesh over 8 years
    @berhir When i will call the GET /api/Account/UserInfo it showing {"Message":"Authorization has been denied for this request."} ,could have any idea,please let me help me
  • Insomniac
    Insomniac over 8 years
    @berhir Hi , i am struck in getting access token , could you please help me . here is the link stackoverflow.com/questions/34036961/…
  • Bimal Das
    Bimal Das almost 8 years
    ok. I am success of getting access token using the url. The problem is, at the RegisterExternal method, on this line: var info = await Authentication.GetExternalLoginInfoAsync(); It returns null, and thus returning a BadRequest().In debugging , I am getting my info. but why it is not giving me null info when everything is current ?
  • Randal Cunanan
    Randal Cunanan over 7 years
    I know this post is old but can you update the answer on how to do this in ASP.NET Core and ASP.NET Identity 3, I can no longer find some enpoints like Account/UserInfo and Account/ExternalLogins on the default template.
  • Himalaya Garg
    Himalaya Garg over 7 years
    You are awesome man... I was searching for this since long.. Microsoft people has made it too confusing by mixing-matching SPA/ MVC/ API templates.
  • Braydie
    Braydie over 7 years
    If I call GetUserInfo again after registering I get a null reference exception because my issuer is LOCAL AUTHORITY after logging in and registering via Facebook (in my instance).
  • Himalaya Garg
    Himalaya Garg about 7 years
    Read the hash part of URL using javascript window.location.hash and get the access_token param from it by splitting params. Hash is not available on server side. You can save the access_token in hidden field to use it later for further requests.
  • Abhishek Jaiswal
    Abhishek Jaiswal almost 6 years
    @berhir Sir, while creating a local account for the user via POST method to RegisterExternal, I need emailid to pass as body. Now, userinfo return Username, not email-id. Any idea, How can I get email-id at this moment? All previous codes are just as you told, and are working fine. Pleasee help.
  • Karthik
    Karthik over 5 years
    How to do this for asp.net core ?
  • Su Ming Yuan
    Su Ming Yuan over 2 years
    I could able to follow the step until RegisterExternal step. POST /api/Account/RegisterExternal. Upon submitting that method, getting NULL response from await Authentication.GetExternalLoginInfoAsync(); Could we try these steps using Postman or need to use html/javascript to following this steps? I've posted the question too. https://stackoverflow.com/questions/70144285/c-sharp-web-api‌​-2-authentication-ge‌​texternallogininfoas‌​ync-return-null