Skip to content
Alban LEROUX edited this page Mar 10, 2012 · 9 revisions

Authentication

A quick introduction

Trust is a difficult part in web communication. Both party need to be sure of:

  • Who is speaking to.
  • Validity of the content exchanged.
  • Keep this insurance during the whole exchange.

This protocol try to respond to that problem.

Algorithms

  • Salt = R( Timestamp / Lifetime ) * Lifetime
  • Secret = K( Public_Key Private_Key )
  • Token = K( Challenge Secret Salt )
  • H(Data) = K( Nonce Data Secret )
  • S(Data) = K( Token Data Secret )
  • L(Data) = serialize(Data)

NOTE:

  • S(X) is called the X signature.
  • H(X) is called the X hmac.
  • K(X) is the MD5 hash of X.
  • R(X) is the next highest integer value by rounding up X — aka ceil() in some programming language.
  • L(X) is the serialization of the data, see above in documentation the serialization algorithm.

The protocol

1: And that's the beginning...

We use a Public_Key for tell who we are trying to authenticate.

We use use a Private_Key, Both are use to create a strong Secret.

We use a Timestamp. Always useful to locate things in time.

You already known:

Timestamp   = 1329866347
Public_Key  = 3123059c1c816471780539f6b6b738dc
Private_Key = 59cc30ad02c25bb7a8757e20d03bd621
Key         = 6fe74546dfa5d730ce5cdfc02fe19dd4

And you are able to calculate:

Secret    = a9283746b094e03e17e4e584fc6a9d8a

2: Solve the challenge...

To authenticate yourself, you have to resolve a Challenge provided by the server: Calculate an authentication Token. This token can be calculated only if you know a Secret. This secret is only known by you and the server.

So only you and the server can calculate that token. Tokens have a Lifetime, by creating a Salt with help of Timestamp and using it in the token generation, tokens have a limited usage in time.

Session is a string of your choice, we talk about it's utility when we start talking about nonce.

Call API auth.request:

>>	Public_Key = 3123059c1c816471780539f6b6b738dc
>>	Session    = Authention Wiki Example
<<	Lifetime   = 300
<<	Challenge  = 2c07899ba4d1b28d70c75a767a0a38c0

And you are able to calculate:

Time         = 1329866400
Token        = 7ed52e0636229a210eea607f7fbf5f10
S(Challenge) = 7ba3d30b361a659fa135307aeaaa9502

3: Prove you are yourself...

Be able to calculate a token proves you know the shared secret, or, once that the token has been transmitted through the web, you're able to intercept this token.

To ensure each part is who he pretend to be, Signature helps.
By signing a content, you prove that you know the shared secret and that you know the authentication token.

So, before use the authentication token in its rôle. Both parts exchange a signature. The client signs the challenge, send it and in the reply, the server signs the nonce provided in the reply.

Each part can verify the signature that he receives and now is sure to talk with the good person.

Call API auth.token:

>>  Challenge    = 2c07899ba4d1b28d70c75a767a0a38c0
>>	S(Challenge) = 7ba3d30b361a659fa135307aeaaa9502
<<  Nonce        = d41d8cd98f00b204e9800998ecf8427e
<<	S(Nonce)     = 303893e7d2e4f29b04f71798887d0720

4: Keep this security...

During the communication, it is important that no one modifies or replays a message by using your token.

So, after the authentication, each message have a Hmac. This time, this is the message which is signed. Hmac ensure that the message is not modified during the communication and that's really you who sending the message.

Hmac is calculate with a Nonce. You get a new Nonce at each valid request in the server's reply. This Nonce protect against a replay attack.

This is here where act Session. Nonce by its function, make obviouly the request/response strean linear. It is impossible to paralelize request because you need the response nonce in the previous one for create the signature of the next one.
API offers to the client to use session and have multiple authentication token at a time. Each session have its own nonce.

HMAC calculation in request

Assume that req.method and req.request are respectively the method and request content of the request

hmac = H(req.method L(req.request))

HMAC calculation in response

Assume that rep.nonce and rep.response are respectively the nonce and response content of the response

hmac = H(rep.nonce L(rep.response))

Serialization Algorithm

Better than long explanation, here we provided a PHP example. This serialization is like json format.

function serialize(array $data = array())
{
	$serial = '';

	foreach($data as $key => $val)
	{
		if (!is_scalar($val))
		{
			$val = $this->serialize((array) $val);
		}

		if (is_bool($val))
		{
			$val = $val ? 'true' : 'false';
		}

		$serial .= sprintf('%s:%s,', $key, $val);
	}

	return sprintf('{%s}', $serial);
}

Format of authenticated dialog

Request

{
	"method"    : "photo.version",
	"token"     : "5f15896d48ad3b0b6c033d769753734a",
	"hmac"      : "fa10c4d7b02a13e27a2ae5a5bbe8130b",
	"request"   : ""
}

Response

{
	"status"   : "valid",
	"hmac"     : "ef30c4d7b02a13e27a2ae5a5bbe0129f",
	"nonce"    : "8ad52e0636229a210eea607f7fbf542c",
	"response" :
	{
		"version" : 0.0.1
	}
}

Token end of life

When a token is too old. You can use the API auth.refresh.

This API method can be called whenever you want. It changes token and nonce authentication. To validate the new token and the nonce you have to calculate the new token, sign it, send the refresh request.
In reply, you receive a nonce signed by the new token. If the signature checking succeed, you knows that now the server have the same new token as you.

NOTE:

You don't have to always check if you're token is too old. When you send a request with a such token. You got in reply a error code old_token. Then you knows you should call now auth.refresh before send again you request.

Specials notes

When you uses query method (GET or POST) for calling the API, you need to pass the authentication data as extra parameters. Here is an example:

	GET http://example.com/api/get/auth.config.set/json/token:5f15896d48ad3b0b6c033d769753734a/hash:fa10c4d7b02a13e27a2ae5a5bbe8130b/?lifetime=30

client example

A PHP API client can be found here: https://gist.github.com/1917812

Here a example of how use it:

	<?php

	require_once 'api_client.php'; // https://gist.github.com/1917812

	class API_client extends Pixelpost_Api_Client
	{
		const API_URL  = 'http://localhost/pp/api/';
		const PUB_KEY  = '3123059c1c816471780539f6b6b738dc';
		const PRIV_KEY = '6fe74546dfa5d730ce5cdfc02fe19dd5';
	}

	$c = new api_client('session name');

	$response = $c->request('auth.config.set', array('lifetime' => 30));

	echo $response->message; // configuration updated

	?>
Clone this wiki locally