Automatically sign AFNetworking api requests with SHA-256 hash signature and timestamp.
Sample usage is available in the example
project.
The purpose of the SHA256 signature is to guarantee that restful API requests are being delivered only by authorized api clients.
For example,
[[APIClient sharedClient] POST:@"/users" parameters:@{@"some" : @"parameters"} success:^(AFHTTPRequestOperation *operation, id responseObject) {
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
}];
will generate a set of auth parameters which can be verified on the server.
{
:some => "parameters",
:auth_timestamp => 1273231888,
:auth_signature => "28b6bb0f242f71064916fad6ae463fe91f5adc302222dfc02c348ae1941eaf80",
:auth_version => "2",
:auth_key => "my_key"
}
AFSignedHTTPRequestOperationManager
reiles on AFNetworking 2.0
and IGDigest
.
Add the following line to your Podfile:
pod 'AFSignedHTTPRequestOperationManager'
Then run the following in the same directory as your Podfile:
pod install
Copy the folder src
to your project.
AFSignedHTTPRequestOperationManager
is a subclass of AFHTTPRequestOperationManager
, so use the class as a normally use a AFNetworking
api client.
#import "AFSignedHTTPRequestOperationManager.h"
@interface APIClient : AFSignedHTTPRequestOperationManager
+ (instancetype)sharedClient;
@end
#import "APIClient.h"
@implementation APIClient
+ (instancetype)sharedClient {
static APIClient *_sharedClient = nil;
static dispatch_once_t onceKosherPenguinToken;
dispatch_once(&onceKosherPenguinToken, ^{
_sharedClient = [[APIClient alloc] initWithBaseURL:[NSURL URLWithString:@"http://www.example.com"]];
});
return _sharedClient;
}
- (id)initWithBaseURL:(NSURL *)url {
self = [super initWithBaseURL:url];
if (self) {
self.responseSerializer = [AFJSONResponseSerializer serializer];
self.clientId = @"CLIENT_ID";
self.clientSecret = @"CLIENT_SECRET";
}
return self;
}
@end
[[APIClient sharedClient] POST:@"/users" parameters:@{@"site_id" : @10} success:^(AFHTTPRequestOperation *operation, id responseObject) {
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
}];
Ruby - Use https://github.com/mloughran/signature
PHP Example
$client_id = 'CLIENT_ID';
$client_secret = 'CLIENT_SECRET';
$auth_version = $app->request->params('auth_version');
$auth_client_id = $app->request->params('auth_client_id');
$auth_signature = $app->request->params('auth_signature');
$auth_timestamp = $app->request->params('auth_timestamp');
if ($auth_version != "2") {
throw new Exception('Incorrect client version');
}
if ($auth_client_id != $client_id) {
throw new Exception('Incorrect client id');
}
if ($auth_timestamp <= time() - (60*60*12) || $auth_timestamp >= time() + 60*60*12) {
throw new Exception('Incorrect auth timestamp');
}
// generate the auth_signature
$params = $app->request->params();
ksort($params);
foreach ($params as $key => $value) {
if (substr($key, 0, 5)=='auth_') {
unset($params[$key]);
}
}
$signatureString = '';
foreach ($params as $key => $value) {
if (is_array($value)) {
foreach ($value as $item) {
$signatureString[] = $key . '[]=' . $item;
}
} else {
$signatureString[] = $key . '=' . $value;
}
}
$signatureString = $app->request->getMethod() . "\n" . urldecode($app->request->getPathInfo()) . "\n" . urldecode(implode('&', $signatureString));
$checksum = hash_hmac('sha256', $signatureString, $client_secret);
if ($checksum!=$auth_signature) {
throw new Exception('Incorrect auth signature ' . $signatureString);
}