I am building a cross platform mobile application (using the Xamarian tools, MonoTouch / MonoDroid). I am trying to work through the authentication workflow and am running into a stumbling block. I have searched all over for a clear answer and have yet to find it.
Here is an overview of my current setup.
I have a web site built in nodejs.
I use passport.js to do oAuth login on the web site. This works great, users can login to my site using Twitter or Facebook.
Now I want to extend this same login functionality to my mobile clients.
I see 2 options
Embed the app id and app secret's in the mobile clients and make direct oAuth calls to FB or Twitter from the mobile app
Proxy the oAuth calls through my existing nodejs web server (keeping the secret keys on the server)
Option 2 appears to be the preferred way (as it avoids having to "ship" the secret in the mobile apps).
I have the proxy approach mostly working.
I open a WebView in my mobile client and point it at http://mysever/auth/twitter
This runs through my existing passport.js code and redirects the mobile WebView over to the Twitter login page.
The user then enters their creds on the twitter webpage on the device.
Twitter then calls my oAuth callback URL (which is my nodejs web server).
My server and Twitter handle the back a fourth handshake of obtaining the user profile information (As I understand it, this is the key to this approach, my server and twitter handle the handshake, the mobile client doesn't have to do anything or pass any tokens during this process)
Here is my problem:
It is this last step that stumps me. Once the handshake is complete on my server I have the user information I need on the server and need to send it back to the mobile client application
I can't figure out any way in the WebView control to grab the response object and grab a cookie, or header value (for instance) (this seems true for Android and iOS). I don't think it is platform specific. I think I am trying to do something that a WebView widget in mobile platforms just don't suport. It makes me think I am missing something obvious.
The only thing I have figured out is to have my web server "redirect" the mobile client browser to a fake URL that has the user info in the querystring. Something like myapp://info?userid=1234
Then in the mobile app I can hijack the URL loading and grab this url and get the data I need. I can then stash this userinfo, close the WebView control and move on to a native screen in my mobile application and user the userinfo in any subsequent REST calls to my nodejs server as a means of identifying the user.
This is massively kludgy for multiple reasons. The biggest of which is that the url is sent over the wire unencrypted and has all the data in plain text.
There has to be a better way to get the data from the web server back to the mobile client?
Or am I doing it all wrong?
The most straightforward way to implement oauth for Xamarin, both for iOS and Android, is using Xamarin.Auth. The starter documentation for the client is here. I think it should maintain everything securely and you will not have to worry about having to use your node server as a proxy.
You will need to provide your Application ID as part of the calls, but I don't there are too many or any security issues to worry about there.
I know this is going against what you already have implemented, but maybe this could help simplify things a bit.
This is the same dilemma that I have been dealing with.
This is how I currently deal with it.
In my app the client can come directly or via another service such as facebook which is my main one and hence the one which I have concentrated on.
Facebook can either redirect via a POST (desk apps) or a GET (mobile).
I check the initial request so see if has a service identifier - here is the facebook GET for example.
app.get('/', function(req, res) {
var paraUrl = URL.parse(req.url,true).query;
//The fb_source is shown -
//i need to go striaght to the facebook authorization since
//its coming from
//from a mobile device.
if (paraUrl.fb_source){
res.redirect('/auth/facebook'); //this is the passport part
return;
}
res.sendfile('index.html');
}
The facebook POST is slightly different in that you get an access token encode in base64url. The GET gives you a code which you can exchange for an access token but I had problems with it and just opted for tying into the passport system.
If a client comes direct I check for the session or a encrypted cookie which ties into the local strategy. This then checks the db for an access token which can used to access the facebook api for example.
If a client is unrecognised they are given the option to authenticate via facebook, google etc.
The main thing is that only 2 pieces of information are stored with the client, the passport session id and my app user id
connect.sid - encypted cookie
userId - encypted cookie
I would be interested to find out how other people are dealing with issue
Related
I've been studying the OAuth 2.0 authorization code flow and am trying to write a React application with an Express backend that displays what a user would see on their own Instagram profile. I'm trying to do so with minimal external libraries (i.e. not using passport-js) and without bringing a database into the mix.
This is my flow as of now:
Resource owner clicks an <a> tag on the React application (port 3000) which redirects them to the /auth/instagram endpoint of my Express server (port 8000)
res.redirect(AUTHORIZATON_URL) sends them to Instagram's authorization server
Resource owner consents and the authorization code is sent back to the predefined redirect-url /auth/instagram/callback with the authorization code set as a query parameter
I strip the authorization code off the url and make a POST request to https://api.instagram.com/oauth/access_token to grab the access token
Now that I have the access token, how do I reach out to the React frontend to let them know that everything worked and that the user was successfully authenticated?
From what I've read, this is where the idea of sessions and cookies come into play, but I haven't had luck finding documentation on how to achieve what I want without bringing in third party libraries.
In the end, I would like for my app to support multiple users viewing their profiles simultaneously. Since I imagine passing the access token to the frontend defeats the purpose of securely retrieving it on the backend, I'm guessing I will somehow need to pass a session id between the frontend and backend that is somehow linked to an access token.
Any ideas as to what my next steps should be are greatly appreciated, as well as any articles or documentation you see fit. Thanks!
Since you're doing the OAuth authentication on the server side, you have to pass some parameter to the redirect_uri, identifying the user session (see: Adding a query parameter to the Instagram auth redirect_uri doesn't work? );
When the redirect uri is called from the authority server, you will know which user was authorized. To notify the browser there are two options: 1) Notify the client using web sockets; 2) Pull the state from the client using a timer triggered function;
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.
I have a Node.js server using PassportJS that uses social login via Google, Facebook, and Twitter.
The Node.js server hosts an API that uses the PassportJS middleware to authenticate routes and securely serve the data. The API exists to serve an iOS application which will be where the user "logs in" through Google, Facebook, Twitter and will subsequently create their account on my service.
How can I accomplish this when the mobile SDKs for the respective companies are for a direct communication between my client and their server? I essentially want a way for my client which talks to my server which talks to their server. Please let me know if the overall idea is incorrect as well.
I believe the right way to do it is to integrate the mobile app with social login, not your website.
Depending what technology you use in your app, you can find libraries to make it easier for you. On your app, it would be a native pop-up, or a simple app-redirect to Facebook app, or Google app or whatever to get the permissions and then a app-redirect back to your app.
You probably dont want a browser to pop out and redirect the user to facebook. A lot of users just use facebook app on their smartphones and they are not even logged-in facebook website in their smartphone's browser.
Once you get the permission and get the user's information, you can securely send those data to your server and store them for future use. You can associate those information with device ID, or generate a token and sent it back to the user's device and store it there for future authentications.
I built an AngularJS application calling some REST API's belonging to my own backend (using Play! 2.2).
I'm using Facebook OAuth client in order to authenticate my users.
As being a Javascript App, my Facebook App Token cannot be "hidden".
Thus, anybody who picked up the Facebook App Token, by just reading the Javascript code could grab a user access token in a "legally" way and therefore use my REST API's.
How could I prevent it?
What is the best practice?
One way would be, I think, to use the server side Facebook's OAuth mechanism, rather than the Facebook Javascript SDK.
In this case, the Facebook app secret would be stored on my server and unreachable from the outside.
But as being a Single Page Application on client-side, I really want to avoid page redirection and benefit of the "popup" feature that comes with Facebook Javascript SDK.
There are a couple of things you can do.
Using the server side ("code") OAuth flow for facebook auth is much more secure. You can still avoid redirects by opening your own popup to initiate the login sequence, similar to what the Facebook JS does (only it goes to your server first).
Enabling HTTPS on your application is usually a good practice...
And if you're worried about cross site forgeries you can implement something like an anti forgery state token. See http://blog.codinghorror.com/preventing-csrf-and-xsrf-attacks/ and also google's instructions here https://developers.google.com/accounts/docs/OAuth2Login#createxsrftoken .
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