• Stars
    star
    143
  • Rank 256,223 (Top 6 %)
  • Language
    PHP
  • License
    MIT License
  • Created about 11 years ago
  • Updated over 5 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Signature generation and validation for REST API query authentication

Query Auth

master: Build Status develop: Build Status

Signature generation and validation for REST API query authentication

API Query Authentication

Most APIs require some sort of query authentication, frequently a method of signing API requests with an API key and signature. The signature is usually generated using a shared secret. When you're consuming an API, there are (hopefully) easy to follow steps to create signatures. When you're writing your own API, you have to whip up both a server-side signature validation strategy and a client-side signature creation strategy. This library endeavors to handle both of those tasks for you.

Sample Implementation

A sample implementation of the Query Auth library is available in order to better demonstrate how one might employ the library.

Usage

There are three components to this library:

  • Request signing
  • Request validation
  • API key and secret generation

Request signing and validation are made possible by the use of request adapters.

Request Adapters

Query Auth request adapters wrap outgoing and incoming requests and adapt them to the request interface that Query Auth expects.

Outgoing

Outgoing request adapters are used to facilitate request signing. There are currently two available in the QueryAuth\Request\Adapter\Outgoing namespace:

  • GuzzleRequestAdapter for use with Guzzle v3
  • GuzzleHttpRequestAdapter for use with Guzzle v4

Incoming

Incoming request adapters are used to facilitate request validation. There is currently one available in the QueryAuth\Request\Adapter\Incoming namespace:

  • SlimRequestAdapter for use with Slim PHP v2

Custom

If you would prefer to use an HTTP library other than Guzzle, or if you prefer to use an application framework other than Slim, you will need to write your own request adapter(s). Please refer to the existing request adapters for examples.

Request Signing

use GuzzleHttp\Client as GuzzleHttpClient;
use QueryAuth\Credentials\Credentials;
use QueryAuth\Factory;
use QueryAuth\Request\Adapter\Outgoing\GuzzleHttpRequestAdapter;

$factory = new Factory();
$requestSigner = $factory->newRequestSigner();
$credentials = new Credentials('key', 'secret');

// Create a GET request and set an endpoint
$guzzle = new GuzzleHttpClient(['base_url' => 'http://api.example.com']);
$request = $guzzle->createRequest('GET', '/endpoint');

// Sign the request
$requestSigner->signRequest(new GuzzleHttpRequestAdapter($request), $credentials);

// Send signed request
$response = $guzzle->send($request);

Request Validation

use QueryAuth\Credentials\Credentials;
use QueryAuth\Factory;
use QueryAuth\Request\Adapter\Incoming\SlimRequestAdapter;

$factory = new Factory();
$requestValidator = $factory->newRequestValidator();
$credentials = new Credentials('key', 'secret');

// Get the Slim request (in the context of a Slim route, hook, or middleware)
$request = $app->request;

// $isValid is a boolean
$isValid = $requestValidator->isValid(new SlimRequestAdapter($request), $credentials);

RequestValidator::isValid() will return either true or false. It might also throw one of three exceptions:

  • DriftExceededException: It timestamp is beyond +- RequestValidator::$drift
  • SignatureMissingException: If signature is missing from request params
  • TimestampMissingException: If timestamp is missing from request params

Drift defaults to 15 seconds, meaning there is a 30 second window during which the request is valid. The default value can be modified using RequestValidator::setDrift().

Replay Attack Prevention

There are a number of strategies available to prevent replay attacks. The strategy in place here follows this general outline:

  • Validate incoming signature
  • If the signature is valid, check the storage layer to see if that combination of API key and signature have been used before
  • If they have, the request is likely a replay attack and should be denied
  • If they have not, persist the API key, signature, and an expiration timestamp
  • Routinely purge records with a timestamp beyond the expiration time

IMPORTANT: The signature expiration timestamp should be greater than maximum allowable drift. Deleting a signature too soon can leave you vulnerable to a replay attack.

NOTE: Implementing a replay prevention strategy is optional. It is not a requirement for using this library. It is, however, highly recommended.

The QueryAuth\Storage\SignatureStorage interface is provided to aid in implementing replay attack prevention.

<?php

namespace QueryAuth\Storage;

interface SignatureStorage
{
    public function exists($key, $signature);

    public function save($key, $signature, $expires);

    public function purge();
}

NOTE: Implementing the SignatureStorage interface is not required to prevent replay attacks, it's simply present to assist you in implementing the attack prevention strategy outlined above.

Key Generation

You can generate API keys and secrets in the following manner.

$factory = new QueryAuth\Factory();
$keyGenerator = $factory->newKeyGenerator();

// 40 character random alphanumeric string
$key = $keyGenerator->generateKey();

// 60 character random string containing the characters
// 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ./
$secret = $keyGenerator->generateSecret();

Both key and secret are generated using Anthony Ferrara's RandomLib random string generator.

Versions Less Than 3.0+ Deprecated, Not Obsolete

While I'd advise upgrading to v3 as soon as possible, a happy side effect of refactoring the API without changing the signature creation and validation logic is that Query Auth 3.0+ is compatible with prior versions of Query Auth. This means that you'll be able to upgrade Query Auth on the server-side (validation) without needing to immediately upgrade all client-side (creation) applications. BONUS!

Installation

Package installation is handled by Composer.

  • If you haven't already, please install Composer
  • Create composer.json in the root of your project and add query-auth as a dependency:
{
    "require": {
        "jeremykendall/query-auth": "*"
    }
}
  • Run composer install
  • Require Composer's vendor/autoload.php script in your bootstrap/init script

Feedback and Contributions

  • Feedback is welcome in the form of pull requests and/or issues.
  • Contributions should generally follow the strategy outlined in "Contributing to a project"
  • Please submit pull requests against the develop branch

Credits

  • Query Auth is my own implementation of the Signature Version 2 implementation from the AWS SDK for PHP 2. As such, a version of the Apache License Version 2.0 is included with this distribution, and the applicable portion of the AWS SDK for PHP 2 NOTICE file is included.

  • API key and API secret generation is handled by Anthony Ferrara's RandomLib random string generator.

More Repositories

1

php-domain-parser

Public Suffix List based domain parsing implemented in PHP
PHP
1,157
star
2

slim-auth

Authorization and authentication for the Slim Framework using ZF2 Authentication and Acl components
PHP
244
star
3

password-validator

Validates passwords against PHP's password_hash function using PASSWORD_DEFAULT. Will rehash when needed, and will upgrade legacy passwords with the Upgrade decorator.
PHP
145
star
4

flaming-archer

Photo 365 application. Built to support my own 365 project and to learn a few new technologies.
Puppet
78
star
5

slim-auth-impl

Example implementation of Slim Auth.
PHP
31
star
6

query-auth-impl

Example implementation of query-auth library
Puppet
12
star
7

tdd-by-example

Exercises from Test-Driven Development By Example by Kent Beck
Python
9
star
8

phpctagger

Create ctags file for your project library and composer dependencies
PHP
7
star
9

ultra-facade

Demonstrates the proper use of an UltraFacade Facade to create SPL Iterators
PHP
6
star
10

refactoring-fowler

Video store example from Chapter 1 of Refactoring by Martin Fowler.
Java
5
star
11

lbtaas

Little Bobby Tables as a Service
PHP
5
star
12

tdd-in-php

Code and tests from my TDD in PHP presentations
PHP
4
star
13

exception-interfaces

Exception Interfaces for PHP
PHP
4
star
14

12-tdds-of-christmas

Excercises from the 12 TDDs of Christmas implemented in PHP.
PHP
4
star
15

resume

My resume
3
star
16

vagrant-manifests

Vagrant manifests
Ruby
3
star
17

logging-demo

Playing around with PHP logging
PHP
2
star
18

bookshelf

PHP 101/102 presentation sample code
PHP
2
star
19

ninjadeveloperclub

Ninja Developer Club
CSS
2
star
20

vim

Personal vim setup
Vim Script
2
star
21

puppet-modules

Puppet modules
Puppet
2
star
22

doctrine-debug-helper

Convenience wrapper around \Doctrine\Common\Util\Debug::dump()
PHP
2
star
23

jeera

Demo ZF app
PHP
2
star
24

projecteuler

Solutions to Project Euler problems
PHP
1
star
25

caldav

PHP
1
star
26

programming-challenges

Programming challenges: Katas, Reddit's daily programmer, etc.
PHP
1
star
27

spaz-api

The Spaz webservice API
PHP
1
star
28

lcthw

Exercises from c.learncodethehardway.org
C
1
star
29

int-or-not

Code and tests from CSI: PHP's "The cure is worse than the disease"
PHP
1
star
30

test

test jquery
JavaScript
1
star
31

TableBuilder

A family of PHP classes that enable you to easily define the various components that make up a complex, dynamic HTML table, as well as the data behind it. This data can then be exported to JSON for client-side rendering.
1
star