3
votes

So I have a Single Page Client App.

Normal flow:

App -> OAuth2 server -> App

We have our own OAuth2 server, so people can login to the app and get an access_token associated with the User entity. http://api.com/oauth2/auth?access_token=X&redirect_uri=http://app.com&response_type=token

Our special flow..

We also have this special endpoint /oauth2/vendor/facebook/auth?client_id=Xredirect_uri=http://app.com

App[1] -> OAuth2 server[2] -> Facebook[3] -> OAuth2 server[4] -> App[5]

[2]: We urlencode the redirect_uri and pass it as a custom parameter to facebook, so we can redirect to http://app.com later on..

[3]:

We redirect the Client to facebook for authentication and acccept app.

[4]:

  • Facebook redirects to oauth server, we get the 'code'.
  • We ask for an access_token, we get the access_token. This all happens behind the scene with CURL.
  • We ask our own API (internal API call to localhost) with a custom grant type (we name it http://api.com/facebook per oauth2 specification), this. This is done with a client secret and is happening behind the scene with CURL.
  • We redirect to the original redirect_uri, originally provided.

It this an applicable way of authenticating with facebook as well?

We know that this can be done in another way, e.g. the Browser first asks for a facebook token, then the browser asks for an access_token that finally gets passed to our own oauth2 endpoint for further validation and processing, that's two requests for the client which to me seems rather slow and cumbersome to me. Or is it?

1

1 Answers

3
votes

Yes, this is an acceptable way. It is an example of what is called "federation".

Federation is of course best known from its implementation in WS-Federation. But you can do it with OAuth too, even if the way in which it is done is not standardized. It has been done before, for example in The Identity Hub.

Just a few remarks tough:

In step 4, you exchange the Facebook code for an access token and a refresh token. Then you need to make an additional call to Facebook, to obtain the profile of the user (or at least their user id). You'll need this so that when the user comes back later, you know that it is the same user. If you plan on calling the Facebook API later (e.g. to check for an updated profile) you need to store the access token and refresh token in your authorization server, associated with the Facebook user id.

In other words, you need to have some internal mechanism that maps Facebook user id's to your own internal user id's. If you exclusively use Facebook for authentication, the Facebook user id and your internal user id can be the same. You can use an internal mapping table, or you can prefix Facebook user id's with e.g. "facebook:". This is similar to what WS-Federation calls the original issuer.

Then you say

We ask our own API (internal API call to localhost) with a custom grant type (we name it http://api.com/facebook per oauth2 specification), this. This is done with a client secret and is happening behind the scene with CURL.

That sounds weird to me. First of all, you are already in the authorization server. Surely you can call an internal function without having to go through the HTTP stack? That would be much more efficient. Furthermore, always avoid secret, internal HTTP(S) endpoints for security reasons. Not only are they not required, you also increase the attack surface and you need to spend time securing them.