NodeJS Confirm Facebook Credentials - facebook

In this scenario I have an app in which:
The user is to log in using Facebook Single Sign On (SSO) on a mobile device (iOS in this case).
The returned Facebook credentials are then sent to a NodeJS server (using the same Facebook App Key) and need to be validated as truly being that users Facebook credentials before they are associated to a program based account.
The Problem:
Given access to everything returned by Facebook as the result of authentication, how can this data be used to confirm that authorization with Facebook?

There are two things you can do:
Facebook will generally pass you a signed request which you can check with a basic SHA2 hash. If the hash is correct, you can assume the user was really authenticated using facebook.
Facebook will generally also pass you a (short lived) access token which you can exchange for a longer lived access token using the graph api. Upon this exchange completing you are as sure you can be that the user is who he says he is.

https://graph.facebook.com/me?access_token=TOKENGOESHERE
If a user is returned, and their ID is what the client claims, they are most likely who they say they are.

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.

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?

Is using the Facebook access token a secure way to validate a user?

On my app the user can sign to Facebook and the app then has the user's access token (say it's 'abc'), I want to use this token to create a user on my own server.
Is it safe to send this access token to my server (using SSL), then get the user's username and ID using https://graph.facebook.com/me?access_token=abc on my server and check that the application the token belongs to is mine with https://graph.facebook.com/app?access_token=abc. If it is my application I then store the user in my user's database and/or log them in.
Can this system be fooled? Can you think of a way someone could log in as someone else?
You should check out all of the Authentication documentation and the Oauth spec to see the different auth flows available
Broadly speaking, you can create a user on your server based on the access token, and be reasonably certain that when you get an access token from Facebook for the same user ID that it's the same person.
If you require very high security for the app you can take steps to ensure the user's access token wasn't produced via malware or the Facebook user being tricked, there's an example showing protection against CSRF in the Server Side Authentication documentation, and there's also a reauthentication flow you can use
I assume that you are using facebook sdk for this, if so the facebook sdk takes care of the security for you and you don't have to worry about a thing.Supposing that you are accessing the api without the sdk then there are two things that must be noted:
1) Auth token expires frequently(facebook has taken great pains to ensure that the user is protected)
2)Making a request with just auth token is not enough there are some other parameters that are needed that can't be faked especially if you are doing this server side since an extra layer is added that fb calls server flow authentication
3)On top of that there are a lot of permissions that are in place that the user has to give in order for an application to access some data.The link below provides a nice article on authentication you can take a look
https://developers.facebook.com/docs/authentication/
So long story short it is safe.

ColdFusion Facebook Integration

I have an app with a login screen with a button that invites users to login using facebook.
That authentication part of the integration works fine. I have also parsed the returned cookie variable to obtain the userID. The next step is to obtain the users information.
I found this stackoverflow article Difficulty parsing string with Facebook one click sign on and ColdFusion which says
Once you get parsed signed_request (stored in your cookie) you can use
user_id (which is Facebook User Id) and oauth_token (aka access_token)
to get needed info via Graph API or FQL.
But, how do you obtain the access_token the poster speaks of? It is not in the cookie variable (that I can see anyway).
Sorry for being such a noob. I got twitter working easy. Facebook is a pain.
https://developers.facebook.com/docs/authentication/ is your friend. Read the server side flow section.
"If the user presses Allow, your app is authorized. The OAuth Dialog will redirect (via HTTP 302) the user's browser to the URL you passed in the redirect_uri parameter with an authorization code:
http://YOUR_URL?code=A_CODE_GENERATED_BY_SERVER
With this code in hand, you can proceed to the next step, app authentication, to gain the access token you need to make API calls.
In order to authenticate your app, you must pass the authorization code and your app secret to the Graph API token endpoint - along with the exact same redirect_uri used above - at https://graph.facebook.com/oauth/access_token. The app secret is available from the Developer App and should not be shared with anyone or embedded in any code that you will distribute (you should use the client-side flow for these scenarios).
https://graph.facebook.com/oauth/access_token?
     client_id=YOUR_APP_ID&redirect_uri=YOUR_URL&
     client_secret=YOUR_APP_SECRET&code=THE_CODE_FROM_ABOVE
If your app is successfully authenticated and the authorization code from the user is valid, the authorization server will return the access token:
In addition to the access token (the access_token parameter), the response contains the number of seconds until the token expires (the expires parameter). Once the token expires, you will need to re-run the steps above to generate a new code and access_token, although if the user has already authorized your app, they will not be prompted to do so again. If your app needs an access token with an infinite expiry time (perhaps to take actions on the user's behalf after they are not using your app), you can request the offline_access permission."

Facebook Javascript API: matching a login to a user

When using the Javascript API login, it returns to the page with a number of parameters, like the access token, the user ID, and other details. If I wanted to associate a user in my database with this Facebook user, which would be the piece of data I want to store to be able to look it up later for authentication?
In other words, which token should I store, so that next time the user logs in, I can look in the database for this token and authenticate the user?
I would use the UID, but it seems easy to spoof another UID and impersonate someone else.
Thanks!
Client side spoofing is not your concern. If you are displaying FB content based upon FB authentication, then FB is responsible for the integrity of that process.
If you are using this info server side, then you need to follow the OAuth 2.0 flow which is not spoofable (to my knowledge) because you are going directly to FB for authentication.
You can't mix the two flows because you leave yourself vulnerable to attacks.
And to answer your other question, yes, you should link your DB to the UID because the access_token will change.
You can validate the fb access token with the fb js sdk. So you can take the fb-uid as save. The tokens you get from fb are only valid for a limited time, so you shouldn't save them.
UPDATE:
Regarding the saveness of the fb-uid: Your PHP script gets a signed request from facebook. That request is signed with your app's secret so that no one else can read that data. The request contains a fb-session for the current user (including the uid) and an access token.