Hello there. Could anyone please give me a walk-through on API authentication?
I just wrapped up building a few different APIs and used https://github.com/tymondesigns/jwt-auth. Its worked out really well.
I'm trying to figure this out too. Will share when I have more details.
Remco Boerma
CTO@NPO, python dev, dba
Authentication. How far do you want to go? It mostly boils down to this: do you know who you want to talk to? If you have a public api, authentication might be a non issue. But if you want to give someone write access to some api you need to be certain it's the right person. Now here comes the trick: do you know up front? Or you do have to rely on some kind of trust? In case of the latter, go for PGP and other certificate based signing tools. But since we are talking API's - more often than not it's too complicated, to much hassle to use trust. And the calculation costs way to many cpu cycles for public key encryption to use stateless..
For my web api's I mostly use a preshared key (sent beforehand preferably using different media). The preshared key is what's at the heart of the "agreement" which is used to "sign" a payload.
Mind you, authentication is just about knowing it's really Bill Gates you're talking to, and not Mr X. - encryption is a completely different story, in which case you don't want others to read what's being sent across the net). Now, if i would just "sign" the payload with the preshared key directly, when someone sniffs it from some insecure line (or old skool evesdropping) security fails. (That's the problem with HTTP BASIC authentication - it's plain text sent across the net).
Back to the signing. I have a pre-shared-key. So i make up a key, give it to you and say "Start with this preshared key. Then calculate the current UTC datetime stamp in seconds sinds the unix epoch (aka linux timestamp). Integer divide that timestamp number by 5*60=300. Append the decimal representation to the key. Next, add the entire message you want to send to me. Next apply some hard to grasp logic to it, called hashing which calculates a "unique number". Use SHA-256. Now send me the letter and the calculcated "signature"..
When i get your message i'll do the same: start with the preshared key, calculate the utc linux timestamp / 300 and add it, add your message and feed it all to the hashing blender. It'll produce a number. It should be the same. If it isn't , i'll try again, but substract 300 seconds from the timestamp because maybe our clocks aren't in sync, or the message crossed the lapse period while being transfered over the net. If the number fits, i'll assume i can trust who has sent me the message.
Since i didn't send the preshared key over the net, only you and i know about it and even a sniffer will have a hard time figuring out what is the root of the signing. Because we used the timestamp the message signature is only valid for 5*2==10 minutes, and hinders replay attacks as well as providing some "salt" to frustrate someone computing what the preshared key is. Because i try to calculate the number two times if at the first time it fails, i skip a lot of errors with servers being out of sync or slow transfers. Because we use UTC time we have a coordinated timezoneless number to work with we all know around the globe.
Since we're all devs here, here's the much shorter while even documented code code we all understand and comprehend (though a little bit different then from the story above, this is highly readable and useable):
It could be written better, but it grew overtime into this. Feel free to rewrite and shorten and paste here :) Also note that in this implementation I use
h.update(payload*10)which works well only to get more random numbers signs. It is "less efficient" when the payload is a gigabyte of data. Also, the above usesmd5as a hashing algorithm and the SHA- family seems to be more secure. But since that's mostly relevant when people have the time to bash against some bit to come up with colliding hashes, I consider it hardly a problem when you use a time-frame of roughly 30 seconds (times 2 because of the retry means a minute of validity)All I need now is a payload and a token. And you can use any rEST, jsonrpc, xmlrpc, soap, http, whatever protocol to send them both over the wire. Preferably secured, but as stated before, that's another topic.
Since both the client and the server calculate the signature you use
calculate_signatureon both the client and the server over the same message. Easy.I hope this helps. Feel free to update it to an sha-256 compatible snippet (using
hmac.new(...,digestmod=hashlib.sha512)i guess, but that's untested)And always, keep you clocks in sync :) No seriously, it bugged me more then once!