Building your own REST API with OAuth 2.0 (II): The good, the bad and the ugly

good-bad-uglyIn the previous post of the series, we explored the basics of OAuth authorization. In this post, we will propose three possible alternatives for implementing authentication using a REST API backend and a mobile frontend. Let’s remember our scenario:

You are developing a RESTful API as the backend for a mobile App frontend. The App will communicate with your REST API to perform CRUD operations on the data. You will allow the user to authenticate against the REST server by a common username/password scheme and you will also allow social login, by means of the usual “login with Facebook” or “login with Twitter” buttons on your App. You want to integrate the social authentication seamlessly into your App User Experience. Once logged in, the App will communicate with the REST API in behalf of the user to do the CRUD operations.

When faced with this scenario in the past, I have developed several alternatives that I call the good, the bad and the ugly. Let’s present them in order of desirability.

The Bad

This method consists in generating the user’s credential from certain parts of the user’s social data and the credentials of your app in that social platform. It’s an adaptation of the Client Credentials flow of OAuth 2, and assumes you have created an App in the social network’s developers site, and you have a client ID and client secret. The process would follow these steps:

  1. You user clicks on the social login icon (Facebook, Twitter, Google+…) and gets asked for authorization to access his basic info.
  2. The user accepts and your App gets some of his info, including his user ID in the social platform, his name, and optionally more data (like the user’s avatar image, email, location…).
  3. The app generates a user ID based on the user’s social network ID and perhaps some other data, and it generates a user’s secret with a combination of the App credentials (client ID and client secret) and the user data, by means of a cryptographically generated string or a hash. This hash should be generated in a way that it would always return the same string for the same user (in a given social network), and it would be impossible to extract the client credentials from the hashed string or infer other user’s secrets by knowing their user’s data alone.

This user’s ID and user’s secret would then be used as the authentication credentials for your REST API. In order for this method to be secure and effective, it is important that the client credentials and exact hashing mechanism are not made public. In order to avoid having the client credentials stored in your App (where they could be retrieved by means of reverse engineering), they can be stored securely in the REST server, and so the REST server will be in charge of calculating the hashed client’s secret and pass it to the App. HTTPs is, obviously, mandatory in this kind of authentication.

Advantages

  • No password are needed, and the user never needs to remember one.
  • Relatively easy to implement.
  • Easy for the user, that just needs to click a social login button.
  • The user’s secret can be stored in the App to allow for quick login, or easily regenerated by just asking for the user’s social data again.

Disadvantages

  • If the client credentials are stored in the App, they could be retrieved by reverse engineering and used to impersonate any user in your REST API. If not, an additional mechanism must be set to assure that the user requesting the user’s secret is actually who he say he is.
  • There is no real authentication. The user is just asked to authorize from his social network’s profile, but anyone with access to the user’s device could impersonate him.

This mechanism is sadly misused by a lot of developers when first faced with the complexities of OAuth. Without a deep understanding of security and authentication, and additional measures, it is easy to implement a custom variant of this scheme that would result in a weak, easy to break authentication system.

The Ugly

This is an hybrid mechanism that uses OAuth as a way of retrieving the user’s data from the social network, and a password for real authentication. This method is marginally better than a pure username/password schema from a user experience point of view, because the user’s identity is automatically selected/retrieved from his social data, but it includes a password that assures a real authentication process, where the user must explicitly demonstrate his identity. HTTPs is mandatory for avoiding the user’s password being transmitted in clear. The process is the following:

  1. Your user clicks on the social login icon (Facebook, Twitter, Google+…), and gets asked for authorization to access his basic info.
  2. The user accepts and his info is retrieved from the social network. The user is presented with a password field.
  3. The user fills the password. Then your App will use some of his data (presumably the user name from the social network or email if available) and the provided password as credentials for your REST Server.
  4. Each restart of the App will retrieve the user’s identity from the social network, and the user would just need to enter his password.

From the point of view of the UX/UI, this method has the advantage that, once the user authorizes the app, he can be presented a personalized view with his avatar image, name and possibly other data, and the user just has to fill a password.

Advantages

  • This method implies real authentication. The user needs to explicitly enter the password in each login, thus assuring his identity.
  • Easy to implement, both in the frontend and in the backend.
  • Easy to integrate in (expand from) a username/password schema.

Disadvantages

  • The user needs to remember another password, thus defeating somehow the social login initial purpose.

This strategy is good if you don’t mind asking you users for passwords, and allows you to avoid prompting the user for all his information. Nevertheless, it is still closer to the username/password user experience than to merely pushing a “Login with Facebook/Twitter” button.

The Good

This authentication mechanism implies forgetting everything about usernames and passwords and embracing another way of thinking about the authentication. The user will not be requested to give a password, neither a secret would be generated to be used as credentials. Instead, we will use a process that some people call “Reverse OAuth authentication”. It consists in obtaining a valid access token from the user’s social network, and then sending it along with the user’s identifier to the REST server. The communication goes through a secure HTTPs channel. The REST server will contact the OAuth authorization server and verify the user’s credentials using the access token. The short-lived nature of this token will assure that the identity of the user is not compromised in the long-term. The main social networks have the following verification endpoints:

  • Twitter: https://dev.twitter.com/docs/api/1.1/get/account/verify_credentials
  • Facebook: https://graph.facebook.com/me

Once the REST API successfully verifies the identity of the user, it responds with the pertinent user object and the API Key for using the REST API. No credentials are needed, and there’s no need for the user to remember a username or password. The API Key can be used until it expires (if applicable) or the user explicitly logs out. When the user needs to login again, it will repeat this process, with another generated short-lived token.

Advantages

  • No need for password or user credentials.
  • Secure for your App. You don’t need to store passwords or access tokens permanently.
  • Easy for the user to understand and use in an App.

Disadvantages

  • There is no real authentication. The user is just asked to authorize from his social network’s profile, but anyone with access to the user’s device could impersonate him.
  • Very difficult to implement and not very intuitive to understand for the developer.

This last mechanism is, in my opinion, the only real way to implement authentication using OAuth authorization, the only one that would not require a password from the user and still guarantee some kind of security and trust for both the user and the REST server. In the following post of this series, I will discuss this last mechanism in depth, explaining it and including complete sources for implementing it on your own REST API server. Have an alternative method? Did I miss something? please let me know in the comments.

Comments(20)

Digital Leaves | Building your own REST API with OAuth 2.0 (III): Hands on
July 10, 2014 At 7:11 pm

[…] the previous post, we presented three alternatives for implementing social login with true authentication (not just […]

Ryan Hoegg
September 30, 2014 At 7:11 pm

I was talking through these approaches with a colleague today, and he asked me a question I couldn’t answer to my own satisfaction. In the “Good” approach, why wouldn’t we just send the actual OAuth access token along with each request instead of generating our own API token to replace it? The original OAuth provider is already handling token expiration for us, and our API can determine the user’s identity whenever we need by using the verification endpoints.

    Ignacio Nieto Carvajal
    September 30, 2014 At 7:11 pm

    Hi Ryan,

    Because that would require our backend server to do a call to the OAuth provider with every single request to our API. That implies an extra delay while our backend server is asking the OAuth provider for the validity of the access token and parsing the results. In a production scenario where you have potentially thousands of users, that solution simply is not convenient IMHO.

    Besides, having your own API token allows you to have control over the security scheme of your backend.

    Best!

Ivan Mushketyk
August 25, 2015 At 7:11 pm

Hi Ignacio,

Thank you for the good article.
I have a few questions about the “Good” method.
1. In the article you write “There is no real authentication. The user is just asked to authorize from his social network’s profile, but anyone with access to the user’s device could impersonate him”. Could you please clarify this point? What would be a real authentication? How is this approach different from a good/old password authentication in a web-app when a server returns a session cookie that is used with every consequent request?
2. You wrote “Very difficult to implement and not very intuitive to understand for the developer”. What is the main source of complexity here? Is it the communication via Auth 2.0 protocol or does the complexity come from managing access token, generation of API Key, etc.?

    Ignacio Nieto Carvajal
    August 26, 2015 At 7:11 pm

    Hi Ivan, thanks to you for reading!

    Regarding your question:
    1. With “no real authentication” I mean that you cannot ensure that the user IS actually the user by just OAuth authorization. Think about this situation, you leave your smartphone with no password in a table, and after one hour, someone enters the room, picks up your phone, opens your App and is shown an OAuth authorization dialog. If you have already entered a password in the OAuth service in the past (which is probably the case given that the App has already been installed and used), it won’t ask for a password again to this person, just a confirmation of the OAuth authorization, and Bum! now this person is “logged” with your credentials in the App, without any authentication required, and it’s impersonating you, thanks to OAuth being used as an authentication mechanism. Meanwhile, a cookie would have probably expired during that hour, so probably that person would have been shown a “Session expired” dialog and forced to authenticate again with a login and a password, thus, the “rogue” user wouldn’t have been able to access your App as you that easily.
    2. Please have a look at the continuation post (http://digitalleaves.com/blog/2014/07/building-your-own-rest-api-with-oauth-2-0-iii-hands-on/). I would say that, for OAuth 1 (like in the case of Twitter reverse auth flow) the complexity lies in the cryptographic generation of all the elements of the OAuth signature and their combination into a coherent flow, whereas in OAuth2 (like in the case of Facebook), the complexity lies in managing the token expiration and the re-authorization behavior without ruining the user experience.

    Best!

Ernesto
November 17, 2015 At 7:11 pm

Muy buen artículo. Después de haber leido mucho y haber implementado esto, la verdad es que lo había hecho por el método “The Good” sin saber que habían otras posibilidades, pero ahora me ha quedado clarísimo.
He utilizado Google Identity Toolkit, pero vamos a cambiarlo y utilizar hello.js (en frontend) y un Java backend con la Java client library que se necesite para cada Oauth server (FB, Google, etc).

Gracias :)

    Ignacio Nieto Carvajal
    November 18, 2015 At 7:11 pm

    Hola Ernesto, gracias a ti por tu comentario, un placer haber sido de ayuda. Un saludo.

Hernan
February 16, 2016 At 7:11 pm

Hey Ignacio,

This is a great article by the way. But there is still a major security problem exposed in this custom authentication mechanism. I’ve gone over several iterations of my app’s authentication scheme, starting with “The Good Method” to end up in a much more complex flow on-hand, simply because OAuth2 is not nearly prepared for the old native + RESTAPI scenario.

The problem in “The Good Method”:
Any application with a user access token can gain access to your API. This basically exposes all of the user’s resources in your app to anyone that can authenticate such user. This defeats the whole purpose of OAuth, as the resource owner would be exposing his resources in your app just by logging in into another application.

There is still a way to make sure the token is generated for your app by using the code flow and/or inspecting the token to make sure the credentials handed by Facebook were meant to your app. But even then, in mobile applications, your app is exposed to many attacks, the most important of which I think is URL Scheme Hijacking, where a new URL scheme gets injected into the device and OAuth redirect_uris for your app end up in another malicious app that receives an access token meant both for your app and your user.

OAuth Authentication is definitely not well thought for mobile clients (A draft is being developed to solve some problems). But certainly, and I think with some risk involved (there is no theoretically correct way to authenticate the user, assuming the REST server is secure and the client device is vulnerable to malicious analysis/tampering), applications like Tinder and Spotify have indeed pulled it off, in an enterprise, massive scale.

I think this is a precious article, mainly because it addresses a very common problem, and a mostly unresolved one. Maybe we can discuss some ways to improve it in that sense. Or maybe you know all this and did not choose to update it.

Cheers,

Hernan

    Ignacio Nieto Carvajal
    February 16, 2016 At 7:11 pm

    Hi Hernan,

    Thanks for your words, and for bringing that into discussion. The situation you describe won’t happen because given the access token, you can easily verify in most OAuth providers if the access token corresponds to the ClientID/ClientSecret of your application, and thus has been generated by your app. Anyway, thanks for pointing this out, because I didn’t explicitly specified it here (I didn’t wanted to enter in too much technical details in this part of the post). Given that HTTPS is properly used, and that ClientSecret is kept secure in the server, I don’t see how this could lead to the attack you describe, can you please elaborate on that?

    In my experience, most applications out there using OAuth for authentication are doing it wrong, but I agree with you that right now, it’s a standard for most applications nowadays.

Matt
February 26, 2016 At 7:11 pm

Hi Ignacio,

Thanks a lot for your post. The good way here seems pretty interesting to me but still does anybody has any source to share for implementing that solution. Working a lot on it this week and didn’t find much informations and sources to implement it.

Thanks in advance.

Matt

Punit Agrawal
March 30, 2016 At 7:11 pm

Great article. Clears out lots of the confusion.
One suggestion though.
For facebook instead of using `https://graph.facebook.com/me` for verifying the token, we should be using `graph.facebook.com/debug_token?input_token={token-to-inspect}&access_token={app-token-or-admin-token}` instead.
This will make sure that the token that is fed into the API actually is generated through the OAuth flow of your app. If its not then that API would return an `OAuthException`.

What do you think?

    Ignacio Nieto Carvajal
    March 30, 2016 At 7:11 pm

    Well, you are completely right. Of course another possibility is using the server side authorization flow, thus asking for the user’s authorization and getting the code that will be exchanged for the access token. This communication will take place in the server, so you know for sure that the retrieved access token is valid for that client_id and client_secret.

Glenn
April 2, 2016 At 7:11 pm

Ignacio, you are a champion.
I’ve spent a lot of time looking through articles trying to get a clear understanding of how OAuth is used for authentication without any success until I reached this article.
Thank you so much for spending the time to put it together, it’s greatly appreciated! I’m looking forward to reading the next article to see the implementation details.
Thanks again!

    Ignacio Nieto Carvajal
    April 20, 2016 At 7:11 pm

    Hi Glenn, glad to help, thanks for your comment!

jakub
May 20, 2016 At 7:11 pm

Hi Ignacio,
I am designing an app based as an angularJS Client with REST API backend services. I have read tons of articles about athorization / authentication now but I am still missing some points :( :
1) is it possible to refresh Access Token (AT) in the IMPLICIT OAuth flow? If not how do you NOT force new login (authentication) after AT expires? Suggesting that AT should expire quickly (let say 1minute?)
2) if using GRANT CODE flow with the REST API what is the best option to store AT and Refresh Token (RT)? shared cache or DB?
3) what do you think about using IMPLICIT flow alltogether with OpenID .
thanks

    Ignacio Nieto Carvajal
    May 22, 2016 At 7:11 pm

    Hi Jakub,
    1. The Implicit OAuth flow doesn’t provide a refresh token. Most OAuth providers won’t require the user to repeat the authentication/authorization step if the user’s already signed on and has authorized your App (i.e: Google, Facebook, etc), so it should be pretty straightforward to repeat the whole access token retrieval process. Anyway, if you need something more permanent (like a refresh/offline token), you probably need to implement a different flow.
    2. I don’t know in AngularJS, but whenever I implement OAuth in node.js, I always store sessions and tokens in database, I think it’s safer.
    3. Sure, it’s been used together in a lot of places. It of course depends on your system’s needs and what exactly do you want to achieve.

      jakub
      May 25, 2016 At 7:11 pm

      Thank you very much for your answers.

      Which flow would you recommend for AngularJS RIA with no server side that consumes data from REST API (completely stateless so far).
      Business requirement is not to “log out/re-authenticate” users from app as long as they are active (even many hours). Users use PKI (clients certificates, pkcs12) for authentication.

Shweta S R
November 15, 2016 At 7:11 pm

Hi Ignacio

This is very informative article which really helps in implementation. I have 2 more requirements

1. After authenticating user, is it possible to retrieve user profile from authorization server.
2. Along with social login can we use OAuth protocol to validate users against active directory.

Regards
Shweta S R

    Ignacio Nieto Carvajal
    December 6, 2016 At 7:11 pm

    Hi Shweta, sorry for my late reply.

    Thanks to you for reading, my pleasure to know it was useful. Regarding your questions:

    1. Well, once you have the proper credentials, you should use them to ask the resource server for the user profile. It’s always a nice idea to have some basic information (like username, api keys, even an avatar, etc) in the authorisation server, so that they can be returned directly on a successful login, but for more advanced/complete user information (i.e: list of written posts in a blog application, list of pending tasks on a TODO application, stats…) in the resource server with a call (like, say /me).

    2. Yes, you can, given that the active directory supports it. Anyway, in the scenario of an active directory, maybe you want to employ a more direct authentication scheme making use of the directory scheme.

    Thanks again!

Leave a Comment

sing in to post your comment or sign-up if you dont have any account.