s0nica
s0nica

Reputation: 1307

Possible approach to secure a Rest API endpoints using Facebook OAuth

I've been reading a lot about the topic but all I find are obsolete or partial answers, which don't really help me that much and actually just confused me more. I'm writing a Rest API (Node+Express+MongoDB) that is accessed by a web app (hosted on the same domain than the API) and an Android app.

I want the API to be accessed only by my applications and only by authorized users. I also want the users to be able to signup and login only using their Facebook account, and I need to be able to access some basic info like name, profile pic and email.

A possible scenario that I have in mind is:

  1. The user logs-in on the web app using Facebook, the app is granted permission to access the user Facebook information and receives an access token.
  2. The web app asks the API to confirm that this user is actually registered on our system, sending the email and the token received by Facebook.
  3. The API verifies that the user exists, it stores into the DB (or Redis) the username, the token and a timestamp and then goes back to the client app.
  4. Each time the client app hits one of the API endpoint, it will have to provide the username and the token, other than other info.
  5. The API each time verifies that the provided pair username/token matches the most recent pair username/token stored into the DB (using the timestamp to order), and that no more than 1 hour has passed since we stored these info (again using the timestamp). If that's the case, the API will process the request, otherwise will issue a 401 Unauthorized response.

Does this make sense? Does this approach have any macroscopic security hole that I'm missing? One problem I see using MongoDB to store these info is that the collection will quickly become bloated with old tokens. In this sense I think it would be best to use Redis with an expire policy of 1 hour so that old info will be automatically removed by Redis.

Upvotes: 24

Views: 6137

Answers (2)

Alec Mather
Alec Mather

Reputation: 858

I know I'm late to the party, but I'd like to add a visual representation of this process as I'm dealing with this problem right now (specifically in dealing with the communication between the mobile app and the web api by securing it with a 3rd party provider like facebook).

For simplicity, I haven't included error checks, this is mostly just to outline a reasonable approach. Also for simplicity, I haven't included Tommy's suggestion to only pass your own custom api token once the authorization flow is over, although I agree that this is probably a good approach.

Please feel free to criticize this approach though, and I'll update as necessary.

Also, in this scenario, "My App" refers to a mobile application.

enter image description here

Upvotes: 0

Tommy Crush
Tommy Crush

Reputation: 2800

I think the better solution would be this:

  1. Login via Facebook
  2. Pass the Facebook AccessToken to the server (over SSL for the android app, and for the web app just have it redirect to an API endpoint after FB login)
  3. Check the fb_access_token given, make sure its valid. Get user_id,email and cross-reference this with existing users to see if its a new or old one.
  4. Now, create a random, separate api_access_token that you give back to the webapp and android app. If you need Facebook for anything other than login, store that fb_access_token and in your DB associate it with the new api_access_token and your user_id.
  5. For every call hereafter, send api_access_token to authenticate it. If you need the fb_access_token for getting more info, you can do so by retrieving it from the DB.

In summary: Whenever you can, avoid passing the fb_access_token. If the api_access_token is compromised, you have more control to see who the attacker is, what they're doing etc than if they were to get ahold of the fb_access_token. You also have more control over settings an expiration date, extending fb_access_tokens, etc

Just make sure whenever you pass a access_token of any sort via HTTP, use SSL.

Upvotes: 36

Related Questions