← Back to Upcase

Rails API, OAuth2 and eating your own dog food philosophy


(Simon Bonnard) #1

Hello,

First, I would like to apologize for my english. I’m not a native speaker.

Background story :

I’m actually working on an API which uses Rails API. That API will serve a logic that a front-end team is going to consume within a Backbone.js application. Yes, we’re planning to eat our own dog food.

First, I started to play on a proof of concept API, which simply used Rails API, AMS, Devise and Mongoid. Users were created via Devise and they were doing requests on the API with their Devise authentication token.

Now, I would like to introduce an OAuth2 provider, which is built on Doorkeeper’s OAuth2 implementation. However I don’t want to install the provider on the same server than the API and I don’t want to play with too many tokens (Devise, Doorkeeper). That’s why I’m actually trying to find a way to avoid that.

By default Doorkeeper creates three collections on MongoDB :

  • oauth_access_tokens
  • oauth_access_grants
  • oauth_applications

On the same MongoDB server I have an users collection. In the User Mongoid model (API side) I added a relationship to the Doorkeeper’s AccessTokens collection.

To sum up, my current architecture looks like that :

  • An OAuth 2 Provider (Doorkeeper) with an access to MongoDB server XYZ.
  • API app : Rails-API + Warden with an access to the same MongoDB server XYZ. That API will be a registered application (with a client_id and secret) on the OAuth provider.
  • A web app built with Backbone.js

I have some issues to consider all the aspects of the ‘eating your own dog food’ philosophy in such a case.

At the moment, I have something which looks like that :

When an user wants to register a new account

  • On the webapp, the user enters its credentials (username + password).
  • Webapp will make a call on API with these credentials.
  • API will create an user on MongoDB and generate an access token for Doorkeeper with an OAuth2 call using the Resource Owner Password Flow of OAuth2 :

RestClient.post("#{APP_CONFIG[‘doorkeeper_app_url’]}/oauth/token",
grant_type: “password”,
client_id: APP_CONFIG[‘doorkeeper_app_id’],
client_secret: APP_CONFIG[‘doorkeeper_app_secret’],
username: params[‘email’],
password: params[‘password’])

That call on Doorkeeper will first authenticate the user AND generate an access token.

  • Then API returns token informations to the webapp. My webapp uses the token to make calls on API.
  • API authenticates the user from the token on each received call. I don’t use session, this is a stateless API.

**When an user wants to sign in **

  • Webapp sends credentials to the API.
  • The API will authenticate the user directly from DB.

Issues and questions

As my webapp only sends credentials to the API which is a proxy to the OAuth2 provider, how am I sure that users will not abuse my API through the webapp flow ? Should I configure a rate-limit system on my own API OAuth2 application ? Or should I totally rebuild the current architecture/OAuth strategy ? Or maybe should I just add an additional security token ?

Thank you.


(Ben Orenstein) #2

I really appreciate that you took so much time to clearly spell out your environment, but I’m afraid I don’t really understand your question.

Are you worried that an attacker will try to brute-force guess users’ passwords through the API? Or are you worried that legitimate users will make too many requests?

Also, is this an existing application with thousands of users or are you building it for a startup?

Thanks for clarifying.


(Simon Bonnard) #3

I’m worried that legitimate users will use their access through our webapp (or directly our API server) to abuse and bypass ‘restrictions’ that would have been applied to them, for example, in the case of a classic third-party application consuming the API. Indeed, users only have to make the same call than our webapp to hijack API’s OAuth application profile. Access tokens are linked to a client_id which is the registered oauth application (in our case the API).

Thats why I guess that there’s something wrong with my reasoning and the current architecture.

I’m looking for a way to consume our own API from a pure javascript application and by using an OAuth2 provider to play the authentication/authorization role. Something similar to the old Soundcloud architecture.

I’m working on a proof of concept. But in the end, this is for an existing application with thousands of users.

I hope that I have been a little clearer and thank you for taking the time to read.


(Joe Ferris) #4

Do the tokens end up being visible to the user?

If you store the bearer tokens on the users collection in your app, the app will be able to make requests on behalf of the user but the user won’t have direct access to the tokens.

My understanding is that even if users have access to their own tokens, they’ll be unable to make requests directly to the API if they don’t have a registered client ID. Access tokens are scoped to an application in Doorkeeper, so without the application key and secret, users can’t make requests directly to your API.

Does that make sense?


(Simon Bonnard) #5

Hello,

For the moment, yes, they’re visible. Indeed, the browser-based app (backbone.js) get the access token from the API and always put that token in the Authorization HTTP header. That’s how the API is able to know (and authenticate) the current user.

You are right. But with the current PoC, users are actually dealing with a web app that only sends a token to the API. Only the API itself has the application key and secret and that’s how a token is created (see the POST request of my first message). Once a user has one token, API and web app will use that token to authenticate the user directly from the database. That’s why I think there’s a huge flaw in the current design. Despite the fact that tokens are scoped to an application (the API here), there’s no way to actually know if an API call is done from the authorised web app or from a non authorised one.

Thank you for your help on that blurry topic.