I'm trying to work out the best architecture for a couple of apps I'm developing.
In both apps I want to utilise google/twitter/LinkedIn/etc to provide authentication of a users identity. The app is composed of an iOS app which has an option to send data to a server which I'm writing in node.js.
I want to utilise either OAuth or OpenId to handle identifying a user against the above servers so that I don't have to put in an authentication system of my own. In other words, allowing users to re-use their ids when choosing to upload data.
I should also note that apart from identifying a user, obtaining a name and email address, I have not intention of using any of their APIs at this time.
I think I have two options:
Place the Authorisation code in the iOS client and transmit some sort of key to the server with the data which it can then verify.
Keep the iOS client fairly dumb, and handle authorisation from the node server.
I'd probably prefer the second option because it means I could centralise authentication and be able to support a web site as well. That's my current theory.
Can anyone who has done something like this give me some pointers as to the pros and cons, OAuth or OpenId, or links to some examples?
In our previous app we opted for a combination of the two approaches. We wanted to centralize our user data on our server in the event we needed to make future API calls on those services. We also wanted the native oAuth experience for the user on the client. Ie: on Android and iOS, the developer can have single sign-on / authorization run through the native Facebook app (if available), vs. popping-up a webview that serves the 'Approve' dialog. It's a better user experience in my opinion. Also for Twitter, the oAuth process may require a PIN code to be entered in the callback which should probably be handled on the client side.
You can pass the access token retrieved by the client to the server for storage and later use if you intend on making additional API calls on these services, provided you expect the token to be long-lived (ie: offline-access permission on FB).
In any case this is mostly a user experience decision.
Related
I'm not sure there is a "proper" way, but before I just bodge together my own incompatible implementation, perhaps there's something in all the standards that can fit my need?
Here's the situation: Apple has declared that apps on their phones MUST include all standard functionality inside themselves. No more iframes with web content! If you need to show stuff from web, open the system browser (Safari)! Unfortunately we need to display stuff from web, so here we go...
Now, the app requires authentication which the user has done previously. We store whatever tokens we need. When the time comes to open the browser, we don't want to force the user to re-authenticate. We need to somehow pass the access credentials to the browser, and preferably do this securely. Furthermore, the webpage in the browser will need a token obtained from our OpenID Connect server.
Unfortunately, the only point of communication between the app and the browser is the URL, so everything that we give will be there, in plain sight. I know that OAuth was pretty worried about this, so much so that they made it impossible to intercept authentication with just the stuff visible on the screen and instead using things like single-use intermediary codes, backchannels and PKCE.
Unfortunately I cannot see any way to use the default flows "out of the box" to achieve what I need. I can think of modifications to those flows that would do it, but I'm not a security expert so I'd rather go with something standard which is vetted by experts.
SCENARIO
It's a good question since many companies want to show existing web content in a secured manner within a mobile app, and to avoid an extra login.
WEB + MOBILE INTEGRATED SOLUTION VIA DISCONNECTED BROWSER?
Ideally what you want to do is pass the mobile app's JWT to the external web content in an HTTP header. iOS APIs such as openURL may not support this however.
You may have to pass a JWT in a query string, in which case I would try to follow a signed request model, though it is not trivial. I have used SalesForce signed requests though not implemented a full solution myself.
Mobile app calls an API method at POST /api/encrypt-token
API returns an encrypted payload that includes the JWT
Mobile app opens a web page at https://mywebapp?token=0a78904cwdu
Web UI calls POST /api/decrypt-token to get the JWT
Web UI stores the token in memory and uses it to call the API
You will want to prevent raw tokens being written to web server logs.
I believe the recommendation for this type pf solution is to use a one time key, as described in the above link. And of course the web session will have some limitations such as silent token renewal not working.
WEB + MOBILE INTEGRATED SOLUTION VIA WKWEBVIEW
In the past I've managed secured web content in a mobile app by making the Web UI get access tokens from the mobile app. This enables an integrated UX and you can use a 'standard as possible' OAuth solution.
When the Web UI runs within a mobile app's web views it no longer does its own OAuth handling and instead calls the mobile app to get tokens and trigger logins
This means there is a single login across web and mobile views, and the Web View gets all the benefits of mobile user experience, such as secure storage of tokens
The Web UI is no longer impacted by things like the web view aggressively dropping cookies
VALID USE OF WEB VIEWS?
Web views are probably not a good long term solution in most cases. I know that Apple are likely to reject apps in 2020 if they use any of these behaviours:
Use of UIWebView - the Cordova default - you need to update to WKWebView
Delivering an app that is solely a repackaged web site with no mobile views
Displaying web content of a dubious nature (ads etc)
I suspect that use of WKWebView used responsibly and justifiably would be accepted. I could be wrong though, so please don't take my word for it.
ONLINE SAMPLES
I will be documenting some stuff about mobile / web integration on my OAuth blog, including code samples.
We have an app that has a backend web service. We are looking to implement a user authentication from our native iOS app to the web server. We want our native app to login to the website, get a token to use for requests and expire this token after a period of time (e.g., after 30 days).
We are looking for sample code to show how to do this for a native iOS app.
For example, do we use a UIWebView with the web login url? An advantage of this is that the user registration, forgotten passwords, etc. code for the web is available to the native app. Otherwise, we would have to re-write the registration, account confirmation, forgotten password code for the native app. If we use the web view approach, what do we save in the native app to verify requests from logged in users?
If we re-implement the registration, verification, forgotten password, login code for the native app, what are the things we need to worry about? What is the best way to implement this code? A sample pseudo or real code is appreciated.
My coworker and I just implemented a web view for login into an enterprise app we are building. You have listed many good reasons for this approach, and it works.
I am not an expert in this area, but I will describe what we accomplished in a matter of several days. Hope it helps.
First, the web login page we display is an existing enterprise login system that supports the OAuth2 protocol. OAuth2 is a pretty popular and secure way to support this type of authentication. There is a ton of information about OAuth2 on the web, and it's fairly complicated, in my opinion. The first key to making us successful was having this enterprise login system already available with OAuth2 support. We didn't write any backend code.
Second, we used this open source library to handle the implementation of the OAuth2 protocol in iOS: https://github.com/nxtbgthng/OAuth2Client
As I mentioned, OAuth2 is complicated to implement. The library takes care of most of the complexity, so the amount of code we had to write was small.
Using the library was a bit challenging, but we managed. The library documentation will get you started, but we found this tutorial extremely helpful in getting it all working:
http://www.idmworks.com/blog/entry/getting-started-with-oauth2client-on-ios
Our solution involves a single login view controller which hosts the web view, and a class to manage the keys and URLs needed to configure the library.
With this approach, authentication is handled entirely by the web view. Upon successful authentication, our view controller intercepts the redirect URL and uses the request token it provides to obtain an access token that can be used to access secure resources. The heavy lifting here is handled by library, and our enterprise login system. Our app has relatively little to do. The library stores the tokens securely in the keychain. It also supports a refresh token which allows for silently refreshing the access token, if your backend supports that.
When our app launches, it navigates to the login view controller if the user is not signed in, or to the main view controller if user is signed in.
ok, I've spent 2 hours googling on what it is & how to use it in a web-application! but no success.
Most of the links talk about scanning codes or entering some key in the GoogleAuthenticar mobile app and it'll return changing verification codes every 30 seconds.
Few things :
The webapplication has it's own login. That means users don't login using Google into the webapp.
If an attacker gets the user's password, he sees the QRcode as the next-step, which he can scan directly with the GoogleAuthenticator app in his mobile (as far as it appears to me). How is it tied to user's mobile only ?
In various sites, it mentions a shared secret between user & server, that means at the time of signup, we provide the user the shared-secret, which he can use in her mobile GoogleAuthenticator app and then use it while reading the QR code ?
In the above case, how to proceed if the secret is lost or forgotten by the user ? Use forget secret to send the secret again to user's email ?
I am confused about how can it be implemented in a fashion when it's a non-google non-android application!
All I get is that, it's just a concept asking for our own implementation with some help from the source-code of the GoogleAuthenticator. Please correct me ?
What I think is the solution is that, we have to write our own mobile-app, just like this guy mentioned here, although I'm still not sure how will the secret between the mobile-app and the server will be unique with each installation of that app such that it identifies a particular user only or is there any way to write our own app and use GoogleAuthenticator mobile app without having Google-login in our webapp ?
Google Authenticator (the mobile application) implements the Time-based One-time Password Algorithm. In the scenario you are asking about, two-factor authentication would work as follows:
The user generates a one-time password to be validated by a server application.
The server would verify the password using the procedure detailed by the TOTP algorithm.
The password generation on the user device can be performed by any application implementing TOTP which has been "configured" for your user account. Configured here means having shared a secret with the server, as you mention yourself in the question.
Now, trying to answer your questions:
The fact your application uses its own set of user credentials or Google's has no direct effect on two-factor authentication. No matter what these credentials are, you need a way to identify your user (the username) in order to be able to proceed to the validation of its TOTP password, because you need to know who the user is. Said another way: using TOTP and using the Google Authenticator application does not imply having to use Google credentials on your site.
I'm not sure I understand correctly. The configuration of the Google Authenticator app for each account is performed only once. If an attacker is sitting right behind your back and takes a photo of your screen while you configure Google Authenticator, then yes, he'd be able to configure its own application with your credentials reading the same barcode you're using. Nevertheless, he'd also need your credentials (proper) in order to perform the login and then provide the one-time TOTP password. Anyway, this is a security problem which stems from how the user improperly handles its own credentials and you could be subject to similar problems no matter the technology you use. To make an imperfect metaphor, it's like asking "if the user leaves the pin card with the codes on the table, an attacker sees it and steals a photo of it, could it use them?". Sure, he could.
Yes, reading the barcode is one of the ways you can configure the application and sharing the secret between the client application and the server. You can use other means, such as entering the key manually into the application, but using the QR code is quicker and much less error prone. You won't even need to generate the QR code, because you could use Google's Web APIs as I explained in the blog post you were reading when you asked me to answer this question. In fact, the Java server side library described there uses the Google Web API's and returns you an URL for the user to check out and read its own QR. If you want to build your own QR logic, go on, but there's no compelling reason you should do that if you're eligible to use Google's APIs (which is something you should check anyway).
If the secret is lost it depends on your own policy, if it's your own application. First of all, you should invalidate the old secret immediately upon user notification. Then, you could use the scratch codes you may have given the user upon creation of the TOTP secret to verify his own identity. If he has lost the scratch codes too, you'd probably want to fall back to some other ways to verify his identity such as using some kind of backup information in his account (backup telephone numbers, security questions, etc.). Once the user identity is verified according to your standards, you would issue a new credential and would begin from the start: that is, reconfiguring the Google Authenticator using a new QR and/or a new secret key.
To summarise: yes, you can use the Google Authenticator application as your client front-end if you want to: there's no need to build another one. The only thing which you should into account is that Google Authenticator uses 30-second windows in its TOTP implementation: the server side logic verifying the TOTP password will have to use the same window size (which is, IIRC, the standard value proposed by the TOTP RFC).
I'm creating a simple iPhone app. The basic premise is that the app will display some data (That I provide online) on the application. The data changes over time, so the app has to draw the data from online and display it. I don't have a significant programming background so I don't want to use my own server.
Thus, I thought it would be significantly easier to just put the data into some documents on a Google account and then access them programmatically via the Google Drive API. I could then update the data in my Drive account and it would get updated in the application. The key here is that I am ONLY accessing ONE account that I own MYSELF. The users' accounts are not being accessed. Therefore the goal is to never have to log in manually. It should all happen behind the scenes, aka, it should look like a server, not a google doc.
With this in mind, it doesn't make sense to show the Google Accounts sign-in page to my users as the standard OAuth2.0 tutorial shows here:https://developers.google.com/drive/quickstart-ios#step_1_enable_the_drive_api
I should be able to access my own data by somehow hardcoding in my username, password etc. Google agrees here: https://developers.google.com/drive/service-accounts#use_regular_google_accounts_as_application-owned_accounts
The above link mentions a "refresh token" that I'm supposed to save. However, I have no idea how to build and save that token, or even for that matter, where to find it.
I've gone through both the basic tutorial and the Dr. Edit Tutorial for iOS, but they both assume that the application is accessing USER accounts not application-owned accounts.
I'm not asking for someone to write the code for me (though tidbits are nice), but if you can point me to a step-by-step guide or related sample code that would help me get started that would be awesome. I'll even come back and post the code that I use!
EDIT: Since I realized that the Google Drive API wasn't something I could use for what I am trying to do, I eventually found Parse which is an awesome tool that handles all the server backend for me and is free at the basic level.
Google APIs objective-C client library doesn't support service (application-owned) accounts, because they are supposed to be used by a server-side apps, instead of clients -- you shouldn't be distributing your private key as a part of an app.
If you would like to distribute content from a service account, maybe you should write a server leg to do the authentication and pass clients credentials in a secure way for them to talk to the API on the behalf of the service account. Or, use Web publishing to make documents universally accessible without authorization and authentication if privacy is not a concern.
we are developing an iOS App using Adobe Flex/Air. The app uses a web service that needs user authentication via facebook login. At the moment, we use server side authentication: There's a login URL displayed in a WebView where the facebook login is done. This way, we get an access_token that can be used on the server side.
This works perfectly but it would really be much better if we could use Single Sign-on with the facebook ios app. As far as I have read, this should work on the client side but I haven't found a way to authenticate the user on the server side.
facebook's access_tokens are valid either for use on the server-side or for the client side so an access_token from the client-side login won't work for the server side.
Thanks in advance for your ideas,
Henk
As far as I can see, you're making this far more complicated than it's really intended to be. Leverage the Facebook iOS SDK, and all of the heavy lifting involved with authenticating the user within your app is handled by the Facebook SDK. There's no need to independently provide sign-in sheets and manage access token exchange between the app's local storage and Facebook's servers without the convenience of the entire Facebook SDK.
This link shows you how to implement SSO natively within your iOS app. It's real simple.
http://developers.facebook.com/docs/mobile/ios/build/#implementsso
Then, I understand that you're keeping authentication information or central user database information on an external server. The best way to synchronize the information between the FB client and your own servers is to simply check the login information returned by the FB SDK with your server after you receive it.
Here's a simple breakdown:
Log the user in using Facebook's standard SDK (see the link above).
In the -didLogin method (or whatever the equivalent is in your Adobe AIR environment), check the access token returned by FB with your server. Not sure what server architecture you're using, but it's safe to say that this will go on outside of the FB SDK. Also, save the access token in your app's user defaults so that the user won't have to login again next time. This whole process should (and inherently will) feel much quicker than it sounds.
If the check with the server returns successfully, notify the user of a successful login. If not, display an error view explaining the reason the user was rejected/not logged in.
Why do it this way? The reason is fairly simple. It's safe to assume that the reason you're having a user login to your app via Facebook is so that you can make requests for the user's Facebook information (i.e. feeds, photos, likes, comments, etc.). The easiest (and best) way to do this is through the FB SDK its self. The SDK takes care of a lot of stuff behind the scenes like access token validation over time, extension of token life, validity of token, and so on. This way, you won't have to worry nearly as much about syncronizing the server information and real-time client information when changes take place. Just authenticate via the FB iOS SDK, and do the rest of your own processing afterward.
Comment below if there's anything I should clarify or even if I missed the point of your question entirely--I tend to get on a roll and may stray from the point. :)
Cheers!
The Kraken