Part 1 covered the basic template security setup. Part 2 focused on the features around local accounts and username/password authentication. This part will deal with third party authentication using Google and friends as well as associating a third party account with a local account.

Social providers typically don’t offer a web service interface for authentication (for good reason), but rather an authentication UI wrapped inside some protocol like OpenID (Connect) or authentication flavoured OAuth2. That means the client application has to use a browser to render those UI parts – typically the login page and some type of consent screen.

This normally works by navigating to a well known URL (the Web API template uses the OAuth2 implicit flow approach) and waiting ‘til a callback on some other well known URL happens. On the callback the access token (plus some metadata) is attached via a hash fragment. What’s happening in between is total up to the authorization server and its coordination with the external login provider. The client does not need to know how that works, which is nice.

The Individual Accounts account controller features an endpoint that queries the registered middleware and tells the client which external providers are available and which URLs it has to use to get the flow going. This information can be used to shape the UI of the client application:

Url is the start URL (the callback URL is hardcoded to the base address in the template) and State is a random number that gets round tripped and should be checked on the callback (see the OAuth2 spec for details). The Url looks like this (sample):

The /api/account/externalLogin endpoint maps to the GetExternalLogin action on the account controller which has quite an interesting combination of attributes:

[OverrideAuthentication]

[HostAuthentication(DefaultAuthenticationTypes.ExternalCookie)]

[AllowAnonymous]

[Route(“ExternalLogin”, Name = “ExternalLogin”)]

This basically means: don’t care about bearer tokens but allow anonymous access or an external cookie(see part 1).

In addition this endpoint also maps to the authorize endpoint of the OAuth2 authorization server middleware (check startup) which is kind of a black belt trick. First the middleware processes the request and then passes it on to whatever framework handles the URL – in this case Web API.

The exact course of events is quite involved. Let’s start with the moment when the web view hits the URL for the first time (check out the source code in parallel):

Access /api/account/externalLogin?provider=Google…

the user is not authenticated

signal the middleware that is responsible for the requested external provider to do the protocol handshake (in this case Google)

The user signs in at Google and does the consent

Google calls back to the Web API using the /signin-google URL

The Google middleware does its back channel communication and sets an external cookie containing some of the claims that came back from Google

the middleware then redirects back to the /api/account/externalLogin endpoint

This time the user is authenticated via the external cookie

The account controller now checks if the login provider / user id combination is already registered in the local database

this is not the case, so the account controller passes control back to the authorization server middleware instructing it to issue a token that contains the claims from Google (external bearer – the claims issuer is Google – again – check part one for the subtle meaning of that).

The callback URL is invoked, and the client application retrieves the access token

At this point the client app has an access token, but it won’t get accepted by default since the claims are not issued by LOCAL AUTHORITY but Google instead. At this point you could open up endpoints by adding:

[HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]

One endpoint that is configured exactly like that is the /api/account/registerExternal. This endpoints accepts the token you get from the previous step and allows it to associate with a new local account (without a password):

Step 1 isn’t even working for me! I tried calling a GET request to /api/account/externalLogin?provider=Google from fiddler and/or my browser and it gives me a 400 bad request error. Calling /api/account/externalLogins?returnUrl (mapped to getExternalLogins) works. So i’m thinking this has to do with the auth server? because it is also mapped to /api/account/externalLogin ?

I’m working in an empty webapi template with individual authentication. All i did was uncomment the google external authentication.

One more question: see at point 3) The callback URL transmits the token back to the client (it’s the second token with claims from local authority). How does the javascript know that this is the token for registered user. I’ve analysed both tokens (for unregistered user, and for registered one) and both of them have the same structure?

I ran into the same problem, and found that the issue was that the URL returned by GetExternalLogins does not contain a trailing slash before the parameters. That is, if you change the URL to /api/account/externalLogin/?provider=Google (note the forward slash right before the question mark) it will work. I have not had any luck whatsoever with fixing this though, and would appreciate any ideas. Hope this helps!

I need to be able to support local account users as well as authenticating against users in Active Directory. Would the individual Accounts Template be the starting point for this? My thoughts would be to use Thinktecture AuthorizationServer as the “relying party to some WS-Federation identity provider”, in my case ADFS.

Sorry forgot to say, I also need to associate the AD user with a local user account (in the same way you describe above). That way I can build an additional set of claims from information associated with the local user maintained in the local database.

I follow your post up to ‘5) The callback URL is invoked, and the client application retrieves the access token’ and everything is clear up to then. However, I call Web API from external MVC application, and after authenticating by Google, would like the user to be redirected back to registration page to fill in all additional details. Only after that, I would like to call api/account/RegisterExternal and pass the complete view model for user registration. How can I redirect user back to the registration page, and retrieve Google access token details at the same time?

I think you can’t because the Web API template is not built for web clients – e.g. the OAuth2 implicit flow that is used there transmits the token via a hash fragment. That would not travel to a server.

You rather want to use the MVC template – which is built for your purpose.

The thing is, my scenario requires MVC application to be hosted outside the LAN, and the API, together with all user details, within it. Are there any options to retrieve token from the hash or pass it using any other way? Do I have any other choices in a given scenario, if I would like to support external login providers?

The thing is, my scenario requires MVC application to be hosted outside the LAN, and the API, together with all user details, within it. Are there any options to retrieve token from the hash or pass it using any other way? Do I have any other choices in a given scenario, if I would like to support external login providers?

UPDATE I found a temporary solution by using javascript to process url hash and call external application. Still cannot get the token itself, since /Token endpoint requires username/password pair. Also, I imagine this approach is not very secure as well?

Knowing the case and being aware that I’m no expert in the area how would you suggest I should approach my scenario. I’m obviously not capable of writing my own authorization server, and would like to use already existing one – MS preferably.

1) From the description: ‘AS deliberately doesn’t do authentication. It solely focuses on authorization’ – I do not really use claims in my scenario, since it’s designed for only one type of users, therefore any authenticated user would be automatically authorized to use the service. Also, would really like to support SSO – so what would you recommend for an authentication service when using Thinktecture AS?

2) I’ve seen your Thinktecture Identityserver 2 – would it be of any use for me? Does it support SSO? Also, as I read it ‘has out-of-the-box support for user management using the ASP.NET membership and roles provider’ – it is not OWIN friendly then, isn’t it?

As I wrote, the documentation for IdServ says ‘has out-of-the-box support for user management using the ASP.NET membership and roles provider’. I thought that MS membership has been replaced by Identity, which brakes dependency on System.Web, therefore is OWIN friendly?

Hi Dominick, appreciate your efforts explaining the individual accounts and external accounts in Web API template.
I’ve question here, can I use the end point “RegisterExternal” without depending on external cookies? Is it possible to get the “ExternalLoginInfo” as the line below from the token not from the cookie?
var info = await Authentication.GetExternalLoginInfoAsync();

Hi Dominick,
I’m trying to add external logins to the Web API I’ve built here: https://github.com/tjoudeh/AngularJSAuthentication/tree/master/AngularJSAuthentication.API
The front-end angularjs app is separate app hosted on different domain other than the back-end api. I’m trying to add/enable manually Google external login in the back-end api.
The problem I’m currently facing that when I’m issuing GET request to the end point “/api/account/ExternalLogin” everything works correctly except the final part which is the redirection (issuing 302 response) to my front end application, so currently I’m not getting the access_token fragment.
I believe it is working seamlessly on the SPA template and Web API/mvc template with individual accounts because the web app is living within the back-end api.

I’m trying to implement this with a Windows Phone app and WebAPI but keep getting ‘Unauthorized’ from my web API after obtaining the facebook access token. I think my process might be missing a step – do you have an accompanying solution example here? I notice it says to follow along with source code but cannot find a link.

The callback URL transmits the token back to the client (it’s the second token with claims from local authority). How does the javascript know that this is the token for registered user? I need to display registration form only when needed.

Hi,
In the AccountController the ExternalLoginCallback gets called once the user successfully logs into the Google account – but how would one exchange the code for the token. I’m using Web Api v2. I’ve also looked at your excellent videos on OAuth on Pluralsight but it some how I cannot seem to see the code where the code is extracted and exchanged for the token and the refresh token

Thank you for providing this blog to the community as I have found it help.

I’m currently working on a project where I have an MVC project (this is mvc with individual account) which serves as my client side/user interface only. The MVC project sends requests to my Web Api project (this is web api with individual user account) to do the work (insert records, get records, insert users, authenticate users, etc).

Currently I’m having problems with getting the external logins working properly on the web api side. I want the web api to do the authentication instead of the MVC.

On the MVC client side, I’ve retrieved the URL of the external provider I want to use, I then send a GET request to the URL of the external provider. This get request hits the GetExternalLogin method on the web api which is what I want to happen because I want the web api to do the authentication (unless what I currently have setup is not proper architecture, please let me know).

(https://localhost:44300 is the url of the MVC project and /Account/ExternalLogin is the method on the MVC client side).

Fiddler captured a 302 response (which I understand is how this should be):

GET /o/oauth2/auth?response_type=code&client_id=51581202790-7hj5vr2f1e4ns25cr6i4jvmn4e4jqg8i.apps.googleusercontent.com&redirect_uri=https%3A%2F%2Flocalhost%3A44301%2Fsignin-google&scope=openid%20profile%20email&state=RnwnkzGrvRB_CqL-wsNtUD1nYeizKCKn1cJCNYbHPRC38DqNyCn_OzwuVOYurp5fwZbB52dp5XdDlHMlDhUtjHKf6njku-jEW6s9unjRR3IsC50qNqTSl5NpFdZkVw_kAN2YYqgj37zLyrnhqpcbSSp4U_7KHLsEnDLGPCIbe24DW3cDwAB6hhAp9SfvZO_dOhwVOCp6iv4cPLFwSPnzLw HTTP/1.1

This is the first time I’m working with ASP Identity, OWIN and Katana technology and perhaps I’m not understanding how this works. I’m a bit stumped. I’ve been doing quite a lot of googling and watching videos on Pluralsight and reading up on the material but I have not been able to find what I’m looking for.