REST API for website which uses Facebook for authentication

40,512

Solution 1

UPDATE: see below

I've been thinking hard about this question too. It's not entirely clear to me yet but here's the route I am thinking of going. I am creating a REST API an my users only auth with Facebook connect.

On the CLIENT:

  1. Use the Facebook API to login and get an OAUTH2 code.
  2. Exchange this code for an access token.
  3. In every call to my custom API I'll include the Facebook user id and the access token.

On the API (for every method that requires user authentication):

  1. Make a request to the /me Facebook graph using the access token from above.
  2. Verify that the Facebook user id returned matches the user id passed to my API from above.
  3. If the access token has expired additional communication is required.

I have yet to test this. How does it sound?

--- Update: July 27th, 2014 to answer question ---

I only use the above exchange once upon login. Once I determine which user is logging in, I create my own access token, and that token is used from that point going forward. So the new flow looks like this...

On the CLIENT:

  1. Use the Facebook API to login and get an OAUTH2 code.
  2. Exchange this code for an access token.
  3. Request an access token from my API, including the Facebook token as a parameter

On the API

  1. Receive access token request.
  2. Make a request to the /me Facebook graph using the facebook access token
  3. Verify that the Facebook user exists and match to a user in my database
  4. Create my own access token, save it and return it to the client to be used from this point forward

Solution 2

This is my implementation using JWTs (JSON Web Tokens), basically similar to Chris' updated answer. I have used Facebook JS SDK and JWT.

Here's my implementation.

  1. Client: Use Facebook JS SDK to log in and get the access token.

  2. Client: Request JWT from my API by calling /verify-access-token endpoint.

  3. MyAPI: Receives access token, verify it by calling /me endpoint of Facebook API.

  4. MyAPI: If access token is valid, finds the user from database, logs in the user if exist. Create a JWT with required fields as payload, set an expiry, sign with the secret key and send back to the client.

  5. Client: Stores the JWT in local storage.

  6. Client: Sends the token (the JWT from step 5) along with the request for the next API call.

  7. MyAPI: validate the token with the secret key, if token is valid, exchange the token for a new one, send it back to the client along with the API response. (No external API calls for verification of the token here after) [if the token is invalid/expired request client to authenticate again and repeat from 1]

  8. Client Replaces the stored token with the new one and use it for the next API call. Once the token expiry is met, the token expires revoking access to API.

Every token is used once.

Read more answers about security and JWT

How secure is JWT

If you can decode JWT how are they secure?

JSON Web Tokens (JWT) as user identification and authentication tokens

Solution 3

I am trying to answer the same question and have been going through a lot of reading recently...

I won't have "the" answer but things are getting a little clearer for me. Have you read the comments in the article you mentioned? I found them really interesting and helpful.

As a result, and in the light of how things have evolved since the first article has been written, here's what I think I'll do:

  • HTTPS everywhere — this allows you to forget about HMAC, signing, nonce, ...

  • Use OAuth2:

    • When authentication requests come from my own apps/website, use this 'trick' (or a variation of it) described in a reply to the article mentioned before.

    • In my case, I have two types of users: those with classic login/password credentials and those who have signed up with Facebook Connect.
      So I'd provide a regular login form with a "Login with Facebook" button. If the user logs in with his "classic" credentials, I'd just send these to my OAuth2 endpoint with a grant_type=password.
      If he chooses to log in via Facebook, I think that would be a two-steps process:

      • First, use Facebook iOS SDK to open an FBSession
      • When that's done and the app is given back control, there should be a way to get a Facebook ID for that user. I'd send this ID alone to my OAuth2 endpoint with an extension grant understood by my server as "using an FB User ID".

Please note that I am still heavily researching on all this stuff, so that might not be a perfect answer... maybe not even a correct one! But I think that would make for a good starting point. The idea of using an "extension grant" for the Facebook authentication might involve having to register it to do things properly? I'm not quite sure.

Anyway, I hope I was able to help you even a bit, and that at least it can start a discussion to find the best solution to this problem :)

Update
The Facebook login is not a solution as pointed in the comments: anybody could send an arbitrary user ID and log in as this user on the API.

What about doing it like this:

  • Show a login form with a "Facebook login" button
  • If this login method is chosen, act kinda like the Facebook SDK: open a web page from your authentication server, which will initiate the Facebook login.
  • Once the user has logged in, Facebook will use your redirect URL to confirm; make that URL point to another endpoint of your authentication server (possibly with an extra parameter indicating the call came from an app?)
  • When the authentication endpoint is hit, the authentication can securely identify the user, retain its FB User ID/FB Session and return an access token to your app using a custom URL scheme, just like the Facebook SDK would do

Looks better?

Share:
40,512
Adam
Author by

Adam

Updated on November 17, 2020

Comments

  • Adam
    Adam almost 3 years

    We have a website where the only way to login and authenticate yourself with the site is with Facebook (this was not my choice). The first time you login with Facebook, an account gets automatically created for you.

    We now want to create an iPhone application for our site and also a public API for others to use our service.

    This question is about how to authenticate with our website from the app/API and is broken into 2 parts:

    1. What is the correct way to handle REST authentication from an API to a website which only uses Facebook OAuth as an authentication method?

    I have read and researched a lot about standard methods of authentication for REST API. We can't use such methods as Basic Auth over HTTPS, as there are no credentials for a user as such. Something like this seems to be only for authenticating applications using the API.

    Currently, the best way I can think is you hit an /authorize end-point on our API, it redirects to Facebook OAuth, then redirects back to the site and provides a 'token' which the user of the API can use to authenticate subsequent requests.

    1. For an official application that we create, we wouldn't necessarily need to use the public API in the same way. What would be the best way then to talk to our website and authenticate users?

    I understand (I think) how to authenticate 3rd-party applications that are using our API, using API (public) keys and secret (private) keys. However, when it comes to authenticating the user who is using the app, I am getting rather confused about how to go about it when the only way we have to authenticate a user is Facebook.

    I feel like I'm missing something very obvious, or don't fully understand how public REST APIs should work, so any advice and help would be greatly appreciated.

  • Adam
    Adam about 11 years
    Thank you for your reply! I had thought about most of what you said but the main concern I had with using the FB iOS SDK and then sending the Facebook User ID was that wouldn't it be easy to send any ID you want to your API endpoint and claim to be another user? This is where I usually end up getting stuck..
  • Olivier Lance
    Olivier Lance about 11 years
    Indeed! That was stupid of me no to think about that... So the solution has to go through your own authentication server somehow...
  • Olivier Lance
    Olivier Lance about 11 years
    I've updated my answer with another solution idea... but just realized you had mentioned it in your original question! I can't see anything else at the moment...
  • Olivier Lance
    Olivier Lance over 10 years
    Hey, that's kind of a late reply, but your solution seems to fix the issue I had in my first answer. Of course you'd have to use HTTPS in order not to send the (id,token) pair on the wire in clear text. But it looks like it should work!
  • Der_Meister
    Der_Meister almost 10 years
    I think it's good to call /me on server and generate your own access token, that will be used by mobile client.
  • Der_Meister
    Der_Meister almost 10 years
    I found that it's bad practice to store FB secret in mobile app. Facebook advices to store it on your server only. developers.facebook.com/docs/opengraph/using-actions/…
  • Nathan Do
    Nathan Do over 9 years
    If we send user_id and access_token to the API server everytime (as post/get params). Will it create security hole if some one is able to intercept the connection ?
  • dcr
    dcr over 9 years
    @NathanDo Use HTTPS between your client and the API server and it shouldn't be an issue if someone intercepts the connection (Heartbleed-type vulnerabilities aside).
  • shreyj
    shreyj over 9 years
    @Chris I am trying to work out same problem and I think your answer does provide a clean solution but - Making a request to /me fb graph - for every method that requires user authentication - Is that not gonna cause significant bump in the response time? Also, it requires that all requests that require auth must be done over https.
  • Chris Greenwood
    Chris Greenwood over 9 years
    @shreyj I've updated the post to address your question
  • Johny19
    Johny19 almost 9 years
    @ChrisGreenwood I need to enable facebook login on my mobile app (my rest api uses aouth2 to authenticate/authorize the users). My first idea was to use the facebook's access token to authorise all the calls made from the mobile app but apparently this is a bad idea. Your solution seems that it will work perfectly. API side, how to you receive the facebook token? Do you process it though a filter? And how do you callt the /me ? do you do it manually or do you use some spring-social apis ?
  • Chris Greenwood
    Chris Greenwood almost 9 years
    @Johny19 Facebook responds with the access token to the URL I specify. Server then grabs the token from the query string. I make sure I exchange it for a longer lasting token then save it in the DB. Then I make a call to Facebook graph's "/me" route using their PHP SDK. I'm not familiar with using Facebook's SDK on native apps but I'm sure their iOS/Android SDKs will let you make a call once you get the access token.
  • Chris Greenwood
    Chris Greenwood almost 9 years
    @Johny19 if the native app receives the token directly, you'll likely have to send it to your API to store it for the current user. You should do this over HTTPS and it wouldn't hurt to encrypt it.
  • PSR
    PSR over 8 years
    I am facing the same problem and like your solutions so far (I've just read it) however I am wondering how it could work for a third party client? Am I correct that it just works the same way? 3rd party requests access token from fb, passes it on to your own API, verification takes place and API access token is provided to 3rd party client for further requests. How would that be safe? Should I really monitor then which 3rd party clients are allowed to use my API and only use trusted once?
  • JVK
    JVK over 8 years
    @ChrisGreenwood check similar, but little different question at stackoverflow.com/questions/30230482/…
  • Dmytro Medvid
    Dmytro Medvid over 7 years
    I made the implementation of described auth process and described it in the question as an answer. stackoverflow.com/questions/37051269/…
  • Peppe L-G
    Peppe L-G about 7 years
    I guess #3 rather should be /debug_token, so you can check that the token actually is for your application.
  • omikron
    omikron almost 7 years
    Do not request access_token in Client. Use "code workflow". Pass code to MyAPI and make another round trip to Facebook to exchange code with access_token. This is explained more thoroughly here: developers.facebook.com/docs/facebook-login/security
  • jimmypage
    jimmypage over 6 years
    can you help with the issue addressed here? stackoverflow.com/questions/42818503/…
  • smg
    smg about 5 years
    Why couldn't you use the Facebook access token in all of your API requests, instead of generating your own custom token format? You could cache the Facebook access tokens on your server to reduce Facebook API requests.
  • davioooh
    davioooh over 4 years
    @ChrisGreenwood Your approach "exhange FB token for my app token" is nice and I'm probably going to apply it in my app, but I have a doubt: what if the FB user is deleted/disabled while my access token is still valid? Is this a valid reason to call /me for every authenticated request?
  • Tim Dowd
    Tim Dowd almost 3 years
    So just to clarify, does the above solution use the facebook auth api to get a short lived access token(OAuth2 code), then we hit our own api with with this token to make a call to the /me facebook graph api endpoint, then once we verify this token belongs to the user and the user exists in our db we then (on api - step 4) create our own access token using our internal authorization providers i.e JWT to allow access around our web api..?