I've been reading the article and I haven't really grasped it yet. When is the private key given to the client?

Say I have a JavaScript client - where would I store this private key (once assigned) - a cookie?

I think that this maybe is done when authenticating a user, if a JavaScript client makes a post request and authenticates a user, the server validates the input and gives back user id ( a public key ) and then some generated string (stored in a table) = the private key?

And then just follow the approach (quoted) from article:

[CLIENT] Before making the REST API call, combine a bunch of unique data together (this is typically all the parameters and values you intend on sending, it is the “data” argument in the code snippets on AWS’s site)
[CLIENT] Hash (HMAC-SHA1 or SHA256 preferably) the blob of data data (from Step #1) with your private key assigned to you by the system.
[CLIENT] Send the server the following data:
    Some user-identifiable information like an “API Key”, client ID, user ID or something else it can use to identify who you are. This is the public API key, never the private API key. This is a public value that anyone (even evil masterminds can know and you don’t mind). It is just a way for the system to know WHO is sending the request, not if it should trust the sender or not (it will figure that out based on the HMAC).
    Send the HMAC (hash) you generated.
    Send all the data (parameters and values) you were planning on sending anyway. Probably unencrypted if they are harmless values, like “mode=start&number=4&order=desc” or other operating nonsense. If the values are private, you’ll need to encrypt them.
(OPTIONAL) The only way to protect against “replay attacks” on your API is to include a timestamp of time kind along with the request so the server can decide if this is an “old” request, and deny it. The timestamp must be included into the HMAC generation (effectively stamping a created-on time on the hash) in addition to being checked “within acceptable bounds” on the server.
[SERVER] Receive all the data from the client.
[SERVER] (see OPTIONAL) Compare the current server’s timestamp to the timestamp the client sent. Make sure the difference between the two timestamps it within an acceptable time limit (5-15mins maybe) to hinder replay attacks.
    NOTE: Be sure to compare the same timezones and watch out for issues that popup with daylight savings time change-overs.
    UPDATE: As correctly pointed out by a few folks, just use UTC time and forget about the DST issues.
[SERVER] Using the user-identifying data sent along with the request (e.g. API Key) look the user up in the DB and load their private key.
[SERVER] Re-combine the same data together that the client did in the same way the client did it. Then hash (generate HMAC) that data blob using the private key you looked up from the DB.
    (see OPTIONAL) If you are protecting against replay attacks, include the timestamp from the client in the HMAC re-calculation on the server. Since you already determined this timestamp was within acceptable bounds to be accepted, you have to re-apply it to the hash calculation to make sure it was the same timestamp sent from the client originally, and not a made-up timestamp from a man-in-the-middle attack.
[SERVER] Run that mess of data through the HMAC hash, exactly like you did on the client.
[SERVER] Compare the hash you just got on the server, with the hash the client sent you; if they match, then the client is considered legit, so process the command. Otherwise reject the command!

On second note, I believe it would be more readable from the article itself...

Am I getting this right?


If the key is being shared by the client and the server, it's not really a private key---it's a secret key. In particular, it's a shared secret.

If the key is a private key, you are using public key cryptography. The private key is made on the server and never leaves the client. The client uses its private key to sign a certificate signing request which includes a copy of its public key. This goes to the server, which rips out the public key, signs it, and sends back a certificate.

Back to your protocol, it looks like you are using an HMAC, which requires a shared secret key. Typically you'll register the shared secret before you start this protocol.


What you're considering is called a "hashing scheme".

  • You're going to take the content of a message and create a hash (i.e. HMAC).
  • The hash will also include a "secret string" that the server provides.
  • The client sends that hash along with the message.
  • The server can re-create the hash from the message, and make sure that its hash value matches exactly the one that the client sent.
  • If it doesn't match, then error out.

The security comes in because a "Man in the Middle" can create a hash for the content, but cannot create a hash that includes the "secret string"... because only client and server know the secret string.

You can get the "secret string" through an out-of-channel communication (like from an email that you cut and paste into configuration, or database, or somewhere, and load it up with the page), or as a one-time request to the server using SSL & cache that somewhere.

  • In the conversations I've participated in around web security, there are a couple of central points that come up.

1) if you give a "secret key" to a browser, it's not secret anymore. Javascript in the browser is just too open to really keep a key secret.

However, if you're not passing nuclear secrets or credit card information, that may be an OK compromise for you. It might be that a hacker won't go to the trouble to upload a malicious script to sniff your secret string. But just bear that in mind.

I remember seeing a javascript implementation of the OAuth 1 hashing scheme with a big disclaimer saying, "Don't run this code in production, because a public browser isn't secure."

2) Some technologies have trouble producing a hash. This doesn't sound like a problem for you, but if you just have plain web pages with no javascript available, or maybe an old Flash script, then you might not be able to make the calculations needed for the hash.

  • The alternative to "hashing" is token-passing.

That means the client gets a token from the server, and sends it along with any requests. The server verifies that it recognizes the token. That means you have to communicate using SSL, because otherwise your token will be visible to the "Man in the Middle" who is sniffing internet traffic. But with SSL it's OK.

Unfortunately, this is a sensitive topic in the security community. OAuth 1 used hashing, but OAuth 2 shifted away from hashing to token passing. This was to defer the cryptographic concerns to SSL, which was doing that anyway. But it's still a pretty contentious issue.

The easiest form of token passing for a browser client is the usual "session" cookie. The client calls the server with username and password, and gets back a "secure" session cookie. Then, as long as the client sends that session cookie with a request, the server can authorize the client's calls.

However, you have to make sure that the "secure" flag is set on the cookie, because you never want to pass it in the clear.

  • OAuth 2 provides a token-passing scheme which adds security by expiring the tokens.

  • The short answer is...

If you don't want to go down the OAuth path, then just a) send username/password to fetch a secure "session" cookie, and then pass that secure session cookie with each request to the server. Have the server check it against the list of secure cookies that it has handed out.

You can get fancier, but that's a basic starting point.

Not the answer you're looking for? Browse other questions tagged or ask your own question.