I wouldn't say I have a solid security background, but there are four best-practices I can think of that would have prevented the security vulnerabilities outlined by this post:

1. Hash the secret API token/key given to each client that is sent to the server with each API request. This will prevent attackers from being able to find out your secret token.

If you only hash the secret token though, this still won't help, as attackers could just send other API requests along with the hashed token. Instead, you will want the client to hash other data unique to the specific API request as well. For example:

http://api.example.com/api_function_name?app_id=my_app&hash={hash_value}&other=stuff

Where the hash_value is computed by the client with something like:

EDIT: Clarified hash_function parameters, thanks @eru.

hash_function( secret_key, api_function_name)

The API server will then receive the request, look up the client's secret_key based on the app_id, and run the same hash_function to make sure it matches hash_value in the request.

This would mean attackers couldn't reuse the hashed value to send other API calls. But they'd still be able to send calls to that function and just change the parameters to the call to get other information from that API call. So, you could also include the other API call parameters in the hash_function as well, which would mean attackers could only replay that exact API call and not change any of the parameters.

You might notice, this is still not good. So, to prevent this "replay attack", you would also generally include the current datetime in the API call as well:

hash_function( secret_key, api_function_name, datetime )

Now, attackers can't even replay the exact request, because by the time they do, the datetime will have changed and so the API server would reject the request if it was replayed later. And since the attacker still doesn't know the unhashed secret_key (since it's never been transmitted in plain text), they can't change the datetime without invalidating the hash_value.

This is theoretical though, because in reality the above wouldn't work well if the clocks on the client and server were at all out of sync (and they probably will be). So, usually, you'd also have to include the current datetime of the request as another parameter in the call to let the server know exactly what datetimestamp was used in the hash_function, and the server will simply make sure the datetime is within an acceptable window of the current datetime on the server. Of course, the bigger the window, the easier to get the API working with clients, but the larger the window for allowing replay attacks.

http://api.example.com/api_function_name?app_id=my_app&hash={hash_value}&other=stuff&time=datetime

And lastly, the chosen hash_function for the API should be something not easy to brute-force (meaning don't make it easy for attackers to listen to a few API calls and be able to reverse-engineer the secret_key, since they'll already know what hash_function is from the API documentation).

OK, 1 was longer than I anticipated, but the others are pretty short.

2. Another more full-proof way to prevent attackers from getting secret tokens, hashed or unhashed, would be to make all API requests work only via HTTPS.

3. Don't provide API (or any) access to user passwords.

4. Don't store user passwords in plain-text, or even via simple hashes. Instead use a cryptographically secure hashing function with salts.