Combined FaceBook client and server side authenticaion - facebook

I have the following use case
My application on iOS is using the FaceBook iOS SDK to authenticate with FB
The application then make a REST call over https to my server to register the FB account to their service account (the service I am offering)
In step 2 the client is sending the FaceBook UID.
My problem is that the server has no FB integration so has to reply on the client sending the right FaceBook UID.
So the problem is obvious, a hacker can attach someone else FaceBook account to their service account .
What I would like is for the server (Java) to be able to validate that the user who is sending the request owns the Facebook UID in question.
I have been searching online and cannot find anything that I think will work.
I came across a vague post about using the FB signedRequest field, this could be passed to the server to validate the user.
Any idea would be appreciated.

Here is a thought:
Once you authenticate the user in your iOS app, get the access_token, and pass only this in your REST call to your server.
On the server side, make a request to https://graph.facebook.com/me?access_token=... using the access_token that you transmitted. If the access token is valid, you will get all the the user's data proving that you have a valid, authenticated user.
If you wanted to be extra sure, you can also request http://graph.facebook.com/app?access_token=... to be sure that the access token was created by your app.

Related

Can I safely authenticate a Facebook user with just Facebook Signed Request?

I want to enable my users to associate their user account with a Facebook or Twitter and allow them to login on my server with their Facebook/Twitter account instead of using the classic username/password. Basically the same idea as the login in StackOverflow.
My current approach for Facebook:
The client application will perform OAuth and then use their Facebook id to login on my server. Based on this Facebook id, the server will lookup the associated user account and perform login without asking for username/pasword. However just relying on the Facebook id to login is not very safe, as that is the same as using only a username to login instead of username & password.
So to make sure the Facebook id is authentic, the client application will also provide a FBSR (Facebook Signed Request, see: https://developers.facebook.com/docs/facebook-login/using-login-with-games/#checklogin) with the login request.
The server will check two things with this FBSR:
The Facebook id in the request must be the same as the one hidden in the FBSR
Server will recalculate the signature part via the Facebook secret key. This must match with the signature in the FBSR .
Normally the server should perform a check with the Facebook server with the oauth_token to be 100% sure of the users identity. However I need skip this in order to avoid dependency to Facebook server on our server.
I have 2 questions:
1) Is this above approach good enough? Can it be improved (without server-to-server communication)?
2) I want to do the same with a Twitter account, but the their signed request is different then Facebook. It seems the Twitter user id is embedded in the oauth_token, so my approach may work with a little tweak, but I am not sure whether the user id is always part of the oauth_token and cannot get this confirmed after searching the internet.
I think that your approach is good enough and don't see any way to avoid server-to-server communication with a signed request. Bear in mind that, with Facebook Graph Api Version 2, in order to protect the privacy of the user, Facebook will send out not the real user id, but one generated for apps. It will also be possible to enable anonymous login.
I am not sure of what you're trying to do with Twitter, and why you compare the APIs (they're quite different). The Twitter login, also know as Sign in with Twitter, used for any website or mobile app, should work for you too.

Facebook, Node & Mobile app - pulling together

I'm trying to build a Facebook-authenticated native mobile app (Windows Phone) that connects to a web service I am creating in Node.
I'd like for a user to:
Log in to Facebook on the mobile app via a native UI or web window
If logged in successfully, create or access server-side user account data tied to that identity
Use the authenticated session to make subsequent authenticated requestsvto that user's data via the native mobile app
My question is: What's the best approach here?
Should I...
Log in the client to facebook locally in the mobile app and pass the Access Token to the node service, and then somehow map the user to my service data based on their facebook account id? That seems grossly insecure if I just pass that token in the URL.
Log the user in via a mobile browser window inside my app, and then redirect back to my Node service in the same window? How do I then make subsequent authenticated requests natively in my app?
Do something else entirely?
Sorry this is so open ended but this is the first time I have tied these things together and although there's a lot of info on each part I've yet to find something that describes the overall pattern / best practice for this design.
Your question is quite opinion based...but still I will try to help.
First of all, you can pass access token in url, its not insecure if you use https. Even if logged into facebook from your mobile app, than also its going to pass a access token in url only. If you mean having the token in http://something.com/access_token, than its not how its should be done.
If you look into the Oauth 2.0 draft you will understand that its done through setting a header Authorization with the value being the token and token_type. Take a good look at the draft.
As your solution I think its fine if you just use the first method mentioned in the question by sending the access token in header as I mentioned in your app and in turn authenticating that token from facebook on each request.
If you think this is just too long a flow for authenticating every request from facebook, than you can get access token by sending request from your mobile app to server and let the server handle the access token and store it in database which you can authenticate each request.
In any case take a look at Passport module, it has facebook and other auth built-in and should be sufficient for your needs.

REST API for website which uses Facebook for authentication

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:
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.
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.
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:
Use the Facebook API to login and get an OAUTH2 code.
Exchange this code for an access token.
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):
Make a request to the /me Facebook graph using the access token from above.
Verify that the Facebook user id returned matches the user id passed to my API from above.
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:
Use the Facebook API to login and get an OAUTH2 code.
Exchange this code for an access token.
Request an access token from my API, including the Facebook token as a parameter
On the API
Receive access token request.
Make a request to the /me Facebook graph using the facebook access token
Verify that the Facebook user exists and match to a user in my database
Create my own access token, save it and return it to the client to be used from this point forward
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.
Client: Use Facebook JS SDK to log in and get the access token.
Client: Request JWT from my API by calling /verify-access-token endpoint.
MyAPI: Receives access token, verify it by calling /me endpoint of Facebook API.
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.
Client: Stores the JWT in local storage.
Client: Sends the token (the JWT from step 5) along with the request for the next API call.
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]
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
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?

Confirming a Facebook Access Token?

We're using the Facebook JS SDK to authenticate users to our application, then sending that information to the server back end to log our user into the application (we support multiple forms of authentication but we can only support FB using a client side flow).
FB is able to log in correctly, I'm able to authenticate the user and everything else, but there's one wrinkle that I'm not sure how to handle, and I'm having difficulty finding anything in the documentation about it. Facebook sends back an accessToken in addition to an id. My question is, how do I verify on the server side that the accessToken is correct for the given id? I want to make sure that the data the user sends us matches what Facebook sent them, and I can't imagine this is that out of the ordinary, yet I can't seem to find any documentation on it.
In the response from Facebook should be a signed_request string that can authenticate that the data is genuine with and decoded to yield the user id and an oauth token for the user.
Passing this along with the other response to your server-side code should allow you to validate everything pretty easily.
May I suggest this answer from another question! It uses try-catch. It is probably the only way to verify that the authentication and the permissions are valid! That's how they do in their examples
Facebook OAuthException: (#1)
I dont think facebook provides any other way of checking

Facebook JS API Login guarantee of user id?

The JS API's FB.login method returns a response with a dictionary of user info, including the user id. That exists client-side in the JS api.
If this is going to be sent back to the server running the facebok canvas app, the server has to trust the user id hasn't been tampered with. As there is no signed checksum that comes back with the response, I can't see how this can be guaranteed.
I can see how you could take the user ID from the POST signed request and store that in a session, but that doesn't seem quite right. I'm sure there's a method for doing this securely that's less baroque than that.
Ideas?
You should use the Server-Side authentication for the server.
When the user loads your app and has yet to authenticate you send him to the auth dialog, when he returns you get a code which you then exchange against the facebook servers to get an access token back, you can then query the graph api for "/me" and get the user data, since you get it from the facebook servers you know it's ok.
In addition, when facebook POSTS to your canvas url you get a signed request which was signed using your app secret, after you decode it you can then check it against your secret key to verify it's authenticity.
In addition the signed request has the user id so you know that's secured as well.
I recommend using both the server side authentication and the client side one, you get different tokens (server is 60 days long, and the client is a few hours) and you can use them both.