iosruby-on-railsobjective-c

Secure API for iOS without user account


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.

Background

Requirements

! Skip to the end for the question if you are losing interest :) !

Ideas thus far

Idea 1:

  1. iOS requests token from web, sending some UUID
  2. WEB responds with API_Token and Token_Expiry
  3. WEB stores UUID, API_Token, and Token_Expiry in database
  4. iOS stores API_Token, Token_Expiry locally
  5. iOS requests data by sending UUID and API_Token
  6. WEB verifies UUID and API_Token, responds with data
  7. Repeat Steps 5-6 until API_Token expires, then repeat from Step 1

*Idea 2: (single use API_Token)*

  1. iOS requests token from web, sending some UUID
  2. WEB responds with API_Token
  3. WEB stores UUID and API_Token in database
  4. iOS stores API_Token locally
  5. iOS requests data by sending UUID and API_Token
  6. WEB verifies UUID and API_Token, responds with data AND NEW TOKEN
  7. iOS gets data and saves NEW TOKEN locally
  8. Repeat Steps 5-7 indefinitely

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).

Question

What suggestion do you have to create a secure API between Rails and iOS?


EDIT 1:

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.


Solution

  • I ended up rolling my own solution based on a few suggestions that I found on the web (see reference links at the end).

    1. iOS checks if it has an auth_token. If no, proceed to step 2, else proceed to step 4.
    2. iOS requests an auth_token by sending a special signature that only my iOS app and servers know how to generate.
    3. WEB validates the special signature and creates a unique auth_token that is saved in the DB and sent back to the iOS app.
    4. iOS requests data by sending the auth_token and a generated signature (again one that only my iOS and server know how to generate).
    5. 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.
    6. WEB responds with the data and a newly generated auth_token.
    7. WEB deletes previous auth_token from DB.
    8. iOS saves new auth_token locally and uses data.
    9. Repeat steps 4-8; If response is 401 unauthorized, restart at step 1.

    References:

    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