is using signed_request on cookie for Facebook server side authentication secure? - security

Yet another Facebook login question.
I am building a one page site that uses Facebook javascript authentication and login. I do not want any page reloads and want to users to login to Facebook at any time. Login to facebook will change my local views (using backbone.js) but shouldn't refresh the page. Although page is not refreshed I want to have server side (threw REST api) to "know" the uid of the user
I have used Server-side authentication before but wish to work only with client side authentication. (for various reasons)
Basically I follow http://developers.facebook.com/blog/post/534/ but my server is node.js
This is how I see the flow: (with restful API)
1. User enter site
2. FB JS SDK login/authenticate user
a. FB SDK has obtained access_token (valid for an hour)
b. signed request is saved in cookie data (fbsr_<app id>)
3. Browser issue any REST API call to Server
a. server looks into cookie to identify uid
Parse the signed_request
Validates sigend_request with application secret
identify uid from parsed signed_request
b. if needed to store long live access token
Server exchange code for tokenA
Server exchange tokenA for longed lived access token (valid for 2 month - fb_exchange_token)
Questions:
why shouldn't I move the access token from client to server instead of signed_request?
is this flow secure?
is it good practice?
Thanks

Related

Giving a user a secret that the backend can't see

Assume the browser-side code is trusted on a website: The frontend is a static website, it's open source, and the loaded files are regularly checksummed. It doesn't send data to the server. For the sake of this argument, just assume the loaded files and scripts are not being maliciously altered by the resource server (Server A).
Now, I'm some other server (Server B) and I want to give the user on this website a secret, for example, an OAuth access token or a JWT, so the user can make requests to Server B from Server A's website. I would prefer to not have the secret be visible to the resource server (Server A).
Is there a way to pass a secret to the user through a redirect or by some other means, without it being shown to Server A?
I can design Server A and Server B, the only security requirement is that Server A should not be able to see the secrets Server B passes to the user of Server A's website.
Refer to the OAuth2 "implicit flow" where the authorization server directly passes the access token to the browser in a hash URL fragment. Hash fragments are never sent to the backend server. However, "implicit flow" is not as secured as "authorization code" flow.
Maybe it's possible to create browser plugin for solving such kind of problems.
OAuth server may associate token with session id on server side (probably keep it in db). When request with oauth token is received server verifies that the same token is in the session.

How to use Passport & JWTs on client-end for authorization?

I'm currently creating a custom CMS for a friend's soccer team. The architecture is as follows:
On the back-end I've an API that interacts with the database (mongoDB).
On the front-end I've an express server that serves the pages using the templating engine handlebars.
Currently I've managed to authenticate requests to the API using Passport and JWTs, which is fine for querying the API, on login I'm storing a JWT with permissions in the cookie storage within the user (it's static pages and not a SPA so I cannot access local/session storage).
My issue is that I am struggling how to implement authorization on the client end for access to the admin panel. Should I decode the JWT on the client-end and read the user role then serve the pages if the admin pages if the user is an admin or should I be sending every request to access the admin section of the front-end to the API for a verification check then serve the files.
Any help would be greatly appreciated, thank you.
I think using a token authentication approach is more suited towards making requests via XHR, rather than hard reloads. The approach you are taking seems to be more suited to a session based authentication strategy. I would use passport-local and authenticate with a user name and password. Once authenticated the user is stored server side in a session variable. You could check the role from that and redirect server side.
If you were to stick with a token you could save it in local storage and then have a script on your admin panel that would first grab the token from local storage and then make a GET request to the server with the token in the header. If the token is valid send back the data to populate the page, otherwise send back an error and redirect from the front end. To get around showing an empty admin panel while checking the validity of the token you could show a loading screen until the request completed.

How do you handle navigation in a token-secured web application?

I have a rather conceptual question, I'm sure it's fairly stupid, but I can't figure it out.
So I am building a simple node.js app to learn, I want to make a web app which is has a set of REST web APIs for everything (including authentication), and then the presentation.
For authentication I am using token-based auth with PassportJS.
So when a user wants to access the site, he'll obtain a token from the authentication API, in turn he'll need to pass this token in a HTTP Header on each request to the app.
My question is, how is this handled in the code? When the app gets the token (for example from a login page which hits the auth API), should it attempt to store it in the local machine (for example LocalStorage, or Cookie) and then on each new page fetch it and use it in a Header? Should each page's javascript attempt to load the token from the local storage automatically? I tried looking for an example, but haven't found a complete one that deals with how you handle navigation when you're depending on sending a header on every single request (that you want authenticated).
Thanks!
Once the user is authenticated return a secure session cookie which will be stored by the user's browser. Now on every request, this cookie will be sent by the browser to your application automatically, which you can check in your backend code (typically controller) to verify the existence of user session.

Google + Authentication without Passport.js

I cant understand the standard flow of authentication and authorization of Google + without using Passport
Requirement:
No passport.js (i know it is simple to use it, but I dont want to use it)
No sessions (will not be using any session, i want to maintain statelessness)
Current architecture:
I had a REST API server, with JWT (JSON Web token),
user will get a access token from my server, when they do a POST /login
my server, will check the username and password and return with access token
this token is needed for future API query in my server
Question:
i) how can I replace my current authentication with Google + ?
ii) when i login using Google + button, I got a access token in my client side, do i send the token back to my server?
iii) but, my server has no information of this user?, do i need first create this user in my server, and when it sends an access token to my server, i will check if this user is valid and return it with my server access token? (so for this user, will not have password information on my server database?, and this access token from google will be stored in my server?)
iv) I read about their doc
they are using sessions, when the user first visit the page, I dont want to use sessiosn
I want to know the general flow, the code I could implement it myself,
I just want to know the common architecture to solve this problem!
It would be great, if you could show me the general concept to deal with this! :)
This is the most recommended way to implement Google+ sign in
Google Hybrid server side signin procedure
To sum it up, there is 2 part;
Retrieve the auth token from Google
Send the Google auth token to exchange for another token from your server
1) To retrieve the auth token from Google, you could use their available SDKs
2) Once you got the auth token from Google, send it back from your client to your server again
3) In your server, exchange the auth token from Google for their access token to allow you to use the Google API on behalf of the user. You could retrieve user information, post Google+ post
4) Generate your own server access token and send it back to the client
5) In your client, save your server generated access token to be used for CRUD from your server

passport.js RESTful auth

How does one handle authentication (local and Facebook, for example) using passport.js, through a RESTful API instead of through a web interface?
Specific concerns are handling the passing of data from callbacks to a RESTful response (JSON) vs using a typical res.send({ data: req.data }), setting up an initial /login endpoint which redirects to Facebook (/login cannot be accessed via AJAX, because it is not a JSON response - it is a redirect to Facebook with a callback).
I've found https://github.com/halrobertson/test-restify-passport-facebook, but I'm having trouble understanding it.
Furthermore, how does passport.js store the auth credentials? The server (or is it service?) is backed by MongoDB, and I'd expect credentials (login & salted hash of pw) to be stored there, but I don't know if passport.js has this type of capability.
There are many questions asked here, and it seems that even though the questions are asked in the context of Node and passport.js the real questions are more about workflow than how to do this with a particular technology.
Let's use #Keith example setup, modified a bit for added security:
Web server at https://example.com serves a single page Javascript client app
RESTful web service at https://example.com/api provides server support to rich client app
Server implemented in Node and passport.js.
Server has a database (any kind) with a "users" table.
Username/password and Facebook Connect are offered as authentication options
Rich client makes REST requests into https://example.com/api
There may be other clients (phone apps, for example) that use the web service at https://example.com/api but do not know about the web server at https://example.com.
Note that I'm using secure HTTP. This is in my opinion a must for any service that is available in the open, since sensitive information like passwords and authorization tokens are passing between client and server.
Username/password authentication
Let's look at how plain old authentication works first.
The user connects to https://example.com
The server serves a rich Javascript application which renders the initial page. Somehwere in the page there is a login form.
Many of the sections of this single page app haven't been populated with data due to the user not being logged in. All these sections have an event listener on a "login" event. All this is client side stuff, the server does not know of these events.
User enters his/her login and password and hits the submit button, which triggers a Javascript handler to record the username and password in client side variables. Then this handler triggers the "login" event. Again, this is all client side action, credentials were not sent to the server yet.
The listeners of the "login" event are invoked. Each of these now needs to send one or more requests to the RESTful API at https://example.com/api to obtain the user specific data to render on the page. Every single request they send to the web service will include the username and password, possibly in the form of HTTP Basic authentication, since the service being RESTful isn't allowed to maintain client state from one request to the next. Since the web service is on secure HTTP the password is safely encrypted during transit.
The web service at https://example.com/api receives a bunch of individual requests, each with authentication information. The username and password in each request is checked against the user database and if found correct the requested function executes and data is returned to the client in JSON format. If username and password do not match an error is sent to the client in the form of a 401 HTTP error code.
Instead of forcing clients to send username and password with every request you can have a "get_access_token" function in your RESTful service that takes the username and password and responds with a token, which is some sort of cryptographic hash that is unique and has some expiration date associated with it. These tokens are stored in the database with each user. Then the client sends the access token in subsequent requests. The access token will then be validated against the database instead of the username and password.
Non browser client applications like phone apps do the same as above, they ask user to enter his/her credentials, then send them (or an access token generated from them) with every request to the web service.
The important take away point from this example is that RESTful web services require authentication with every request.
An additional layer of security in this scenario would add client application authorization in addition to the user authentication. For example, if you have the web client, iOS and Android apps all using the web service you may want the server to know which of the three the client of a given request is, regardless of who the authenticated user is. This can enable your web service to restrict certain functions to specific clients. For this you could use API keys and secrets, see this answer for some ideas on that.
Facebook authentication
The workflow above does not work for Facebook connect because the login via Facebook has a third party, Facebook itself. The login procedure requires the user to be redirected to Facebook's website where credentials are entered outside of our control.
So let's see how things change:.
The user connects to https://example.com
The server serves a rich Javascript application which renders the initial page. Somehwere in the page there is a login form that includes a "Login with Facebook" button.
The user clicks the "Login with Facebook" button, which is just a link that redirects to (for example) https://example.com/auth/facebook.
The https://example.com/auth/facebook route is handled by passport.js (see the documentation)
All the user sees is that the page changes and now they are in a Facebook hosted page where they need to login and authorize our web application. This is completely outside of our control.
The user logs in to Facebook and gives permission to our application, so Facebook now redirects back to the callback URL that we configured in the passport.js setup, which following the example in the documentation is https://example.com/auth/facebook/callback
The passport.js handler for the https://example.com/auth/facebook/callback route will invoke the callback function that receives the Facebook access token and some user information from Facebook, including the user's email address.
With the email we can locate the user in our database and store the Facebook access token with it.
The last thing you do in the Facebook callback is to redirect back to the rich client application, but this time we need to pass the username and the access token to the client so that it can use them. This can be done in a number of ways. For example, Javascript variables can be added to the page through a server-side template engine, or else a cookie can be returned with this information. (thanks to #RyanKimber for pointing out the security issues with passing this data in the URL, as I initially suggested).
So now we start the single page app one more time, but the client has the username and the access token.
The client application can trigger the "login" event immediately and let the different parts of the application request the information that they need from the web service.
All the requests sent to https://example.com/api will include the Facebook access token for authentication, or the application's own access token generated from Facebook's token via a "get_access_token" function in the REST API.
The non-browser apps have it a bit more difficult here, because OAuth requires a web browser for logging in. To login from a phone or desktop app you will need to start a browser to do the redirect to Facebook, and even worse, you need a way for the browser to pass the Facebook access token back to the application via some mechanism.
I hope this answers most of the questions. Of course you can replace Facebook with Twitter, Google, or any other OAuth based authentication service.
I'd be interested to know if someone has a simpler way to deal with this.
I greatly appreciate #Miguel's explanation with the complete flow in each cases, but I'd like to add some on the Facebook Authentication part.
Facebook provides a Javascript SDK which you can use to get the access token on client-end directly, which is then passed to the server and used to further pull all the user information from Facebook. So you don't need any re-directs basically.
Moreover, you can use the same API end-point for mobile applications as well. Just use the Android / iOS SDK for Facebook, obtain the Facebook access_token on the client end and pass it to the server.
Regarding the stateless nature as explained, when get_access_token is used to generate a token and passed to the client, this token is also stored on the server. So it's as good as a session token and I believe this makes it stateful ?
Just my 2 cents..
Here is an awesome article I found that can help you authenticate with:
Facebook
Twitter
Google
Local Auth
Easy Node Authentication: Setup and Local

Resources