I know this is a popular type of question, but I haven't been able to find any other questions that address my specific needs.
<li>I have an iOS app that retrieves data from my Ruby on Rails developed web API.</li>
<li>I would like to privatize my API so that other sources cannot use the data coming from my API (ie. someone else develops an app that hits my API url and uses the data for their customers)</li>
<li>(HARD) Private API so that only authorized clients (coming ONLY from iOS app) can access the data from the API.</li>
<li>(HARD) Users must not have to create user/password accounts.</li>
<li>(SOFT) I have read that SSL can become a nightmare when trying to get apps approved by Apple. Since this is a small-time app (as of now), I prefer to not depend on SSL. <strong>However</strong>, if you can point me in the right direction regarding the ease of using SSL with all API traffic on iOS, I am all ears).</li>
! <strong>Skip to the end for the question if you are losing interest :)</strong> !
Ideas thus far
Idea 1:<ol> <li>iOS requests token from web, sending some UUID</li> <li>WEB responds with API_Token and Token_Expiry</li> <li>WEB stores UUID, API_Token, and Token_Expiry in database</li> <li>iOS stores API_Token, Token_Expiry locally</li> <li>iOS requests data by sending UUID and API_Token</li> <li>WEB verifies UUID and API_Token, responds with data</li> <li>Repeat Steps 5-6 until API_Token expires, then repeat from Step 1</li> </ol>
*Idea 2: (single use API_Token)*<ol> <li>iOS requests token from web, sending some UUID</li> <li>WEB responds with API_Token</li> <li>WEB stores UUID and API_Token in database</li> <li>iOS stores API_Token locally</li> <li>iOS requests data by sending UUID and API_Token</li> <li>WEB verifies UUID and API_Token, responds with data AND NEW TOKEN</li> <li>iOS gets data and saves NEW TOKEN locally</li> <li>Repeat Steps 5-7 indefinitely</li> </ol>
Problems with these ideas
I believe there is no perfect UUID solution for iOS any longer. If the UUID can change over time (or if the user has multiple iOS devices), an authentication problem can occur.
If a hacker gets an API key, I don't want them to be able to access the data (hence the expiry or new token idea).
What suggestion do you have to create a secure API between Rails and iOS?<hr>
I'm still surprised this isn't something that comes up all the time. There must be a ton of apps out there that communicate to an API but do not force user's to sign up. If SSL or OAuth is the only proper solution, please defend. I'm all ears.
Aside from the problem of tracking users across devices, for which I wouldn't know how to provide a reasonably simple and reliable mechanism, other than a Game Center account, let's discuss a simple way of closing your API to other apps.
The handshake would involve your client submitting a URL request that could already include a device-specific token to identify your user. The response from your server will be a random one-time challenge in form of a string. Both the client and the server know a non-trivial function that generates a response string as a function of the challenge and possibly the user token, thus validating the client.
The mechanism is by no means secure but is trivial to implement and will provide some barrier to others. You should definitely validate the form of the user token for some additional protection. For example, if your token is a MAC address, the request must have the form of a MAC address.
I ended up rolling my own solution based on a few suggestions that I found on the web (see reference links at the end).<ol> <li>iOS checks if it has an auth_token. If no, proceed to step 2, else proceed to step 4.</li> <li>iOS requests an auth_token by sending a special signature that only my iOS app and servers know how to generate.</li> <li>WEB validates the special signature and creates a unique auth_token that is saved in the DB and sent back to the iOS app.</li> <li>iOS requests data by sending the auth_token and a generated signature (again one that only my iOS and server know how to generate).</li> <li>WEB validates that the auth_token exists in the DB. It then generates an auth_signature and verifies that the request came from my iOS app.</li> <li>WEB responds with the data and a newly generated auth_token.</li> <li>WEB deletes previous auth_token from DB.</li> <li>iOS saves new auth_token locally and uses data.</li> <li>Repeat steps 4-8; If response is 401 unauthorized, restart at step 1.</li> </ol>
This GitHub Gist by @keighl is what started me off, by far the best example that I found: https://gist.github.com/4336694
Railscast: Securing an API: http://railscasts.com/episodes/352-securing-an-api