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.
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.
I am trying to create an ios App that talks to a backend API written in nodejs. The backend also has an accompanying webapp also written in nodejs. The idea is that you can login (using facebook-js) on either the app or the webapp and post things to to.
My question is this, let's say that the user decided to login using the ios App, then call some backend API method to post an article, how do I make this work without essentially forcing the user to login twice?
Not sure if I'm making sense, any help would be greatly appreciated!
As Facebook uses OAuth for the client authentication, it's relatively easy to store the Access Token resulting from the login process somewhere on your server, and use them later.
Have a look at Design for Facebook authentication in an iOS app that also accesses a secured web service
Also, see https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow/v2.1 which outlines the login process and the storage of Access Tokens.
I have two Rails apps, and I would like to accept user login credentials from one app (say App A) in another (say App B). For the app that's accepting login credentials (App B), I think the best option is to use OAuth. But for the app whose user credentials are being used (App A), how do I allow the user's login information to be used by another site? Do I use OAuth as well, or something like Doorkeeper? As you can tell, I'm very new to user authentication, so any advice would be helpful!
One possible way to solve the problem is to create a doorkeeper-based standalone app that would contain all of a user's credentials. Then your client apps would actually connect with this "auth app" (using Oauth.) Then when the client is authenticated on the Auth App, they get returned to the Client app. Of course, from a UI perspective, you make this seamless, so your login page would actually be on this Auth app, but it would look seamless to the user. This way, you can add as many apps as you want and the credentials would all be in one place. To answer your specific question, you would use Oauth2 on your Client apps and Doorkeeper on your Auth App.
You'll need to tweak the doorkeeper configurations to make this process "clean" to the user. For example for internal apps, you can safely use the skip_authorization method in doorkeeper. Learn more about that here
This doorkeeper/oauth system has the added benefit of decoupling your authentication logic from your main application, which is fundamental to good Service Oriented Design. There are certainly other ways to approach this problem, but given the context of your question, yes, Doorkeeper and Oauth2 would solve your problem.
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
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.