Giter Club home page Giter Club logo

snaggle's Introduction

Snaggle

Build Status Scrutinizer Code Quality Build Status

Snaggle is an OAuth 1 Client Library that can be used to generate signatures and the appropriate OAuth 1 Headers. While OAuth 2.0 is suggested for building a new API, there are still plenty of popular services that use OAuth 1.0.

Installation

Snaggle should be installed via composer:

"require": {
    "mfrost503/snaggle": "1.0.0"
}

OAuth 1.0 Client Examples

OAuth 1.0 requires the use of Access and Consumer tokens, being able to create a valid signature will unlock the content of an OAuth 1.0 APi.

use Snaggle\OAuth1\Client\Credentials\AccessCredentials;
use Snaggle\OAuth1\Client\Credentials\ConsumerCredentials;
use Snaggle\OAuth1\Client\Signatures\HmacSha1;
use Snaggle\OAuth1\Client\Signatures\Plaintext;
use Snaggle\OAuth1\Client\Header\Header;

// first we need to represent our tokens, these should be stored securely
$consumer = new ConsumerCredentials('CONSUMER_KEY', 'CONSUMER_SECRET');

$access = new AccessCredentials('ACCESS_TOKEN', 'ACCESS_SECRET');

$signature = new HmacSha1($consumer, $access)
    ->setResourceURL('https://api.example.com/v1/users')
    ->setHttpMethod('get');

$header = new Header();
$header->setSignature($signature);
$header->createAuthorizationHeader();

There's also a plaintext signature type (which should only be used when there is no other way and over https), it implements the signature interface and uses the signature parent, so it's use is the same as HmacSha1, only the instantiation differs

$signature = new Plaintext($consumer, $access);

This line can be used interchangeably with the signature instantiation in the previous example.

Signatures

This library has an implementation of HMAC-SHA1 and Plaintext signatures, these signatures are used to communicate the identity of the resource owner making the request. Services can have different requirements for how a signature is built, the signatures in this library are built to the OAuth 1.0 spec.

HMAC-SHA1

HMAC-SHA1 is the more secure of the two signature types in this library and is the most commonly used. This signature involves the creation of a base string and composite key that are encapsulate and hash the information required to identify with an OAuth 1.0 service.

Plaintext

Plaintext signatures should only be used over https, because they aren't secure. Services like Twitter don't allow you to use the Plaintext signature, but they can be very handy if you are working with an internal API and the complexity of a signature doesn't provide a real strong security benefit.

HTTP Client

Snaggle does not come with an HTTP client included in the library, the reason for that is there are HTTP Clients that are very well done, but everyone's needs and access to these tools maybe different. Those clients do a great job at the job they're meant to do, which is make HTTP requests. Snaggle's role in this process is to provide the headers that are required to make OAuth 1 requests work properly and handing those off to whatever client you choose to use.

There are a couple different cases when it comes to providing headers to clients. For example, when setting a header in cURL you'll have to send the 'Authorization: ' prefix, but with Guzzle you'll just want the content of the headers. Snaggle gives you the option to generate the headers with or without the prefix. Below is an example of each using Guzzle and cURL:

Guzzle

In Guzzle, we don't want the prefix so the $header->creationAuthorizationHeader() has a parameter $includePrefix that is set to false by default. So here's how you'd use it with a client that doesn't need the header prefix.

$header = new Header();
$header->setSignature($signature);
$authorizationHeader = $header->createAuthorizationHeader();

$client = new Client();
$client->get('https://api.example.com/v1/users', [
	'headers' => ['Authorization' => $authorizationHeader]
]);

cURL

cURL will require the prefix when adding the header to the request. In order to do this, we'll just need to pass the parameter true to the $header->createAuthorizationHeader();

$header = new Header();
$header->setSignature($signature);
$authorizationHeader = $header->createAuthorizationHeader(true);

$ch = curl_init('https://api.example.com/v1/users');
curl_setopt($ch, CURLOPT_HTTPHEADER, [$authorizationHeader]);

By using this approach, we can decouple the generation of the OAuth 1 Headers from the HTTP Client that will eventually be used to send the requests.

Making token requests

One of the more challenging aspects to understand is the token exchange, which is necessary for communicating with a resource server. Essentially there are a number different times where some back and forth communication needs to happen. Here's an example of how you could use this library to retrieve an access token from Twitter.

use \Snaggle\Client\Credentials\ConsumerCredentials;
use \Snaggle\Client\Credentials\AccessCredentials;
use \Snaggle\Client\Signatures\HmacSha1;
use \Snaggle\Client\Header\Header;
use \GuzzleHttp\Client;

$consumer = new ConsumerCredentials('CONSUMER KEY', 'CONSUMER_SECRET');
$access = new AccessCredentials();
if (!isset($_GET['oauth_token']) && !isset($_GET['oauth_verifier'])) {

    $signature = new HmacSha1($consumer, $access);
    $signature->setResourceURL('https://api.twitter.com/oauth/request_token')
              ->setHttpMethod('post');

    $headers = new Header();
    $headers->setSignature($signature);
    $auth = $headers->createAuthorizationHeader();

    $client = new Client();
    $response = $client->post('https://api.twitter.com/oauth/request_token', [
        'headers' => ['Authorization' => $auth]
    ]);
   
    $res = $response->getBody();
    parse_str($res);
    header('Location: https://api.twitter.com/oauth/authorize?oauth_token=' . $oauth_token);

} else if(isset($_GET['oauth_token']) && isset($_GET['oauth_verifier'])) {
    $access = new AccessCredentials($_GET['oauth_token']);
    $signature = new HmacSha1($consumer, $access);
    $signature->setHttpMethod('post')
              ->setResourceURL('https://api.twitter.com/oauth/access_token');

    $headers = new Header();
    $headers->setSignature($signature);
    $auth = $headers->createAuthorizationHeader();

    $client = new Client();
    $response = $client->post('https://api.twitter.com/oauth/access_token', [
        'headers' => ['Authorization' => $auth],
        'body' => ['oauth_verifier' => $_GET['oauth_verifier']]
    ]);

    $res = $response->getBody();

    // parse_str will create variables called $oauth_token and $oauth_token_secret
    parse_str($res);
    $token = $oauth_token;
    $secret = $oauth_token_secret;
	// You will need to persist these values at this point
}

Notes

OAuth 1.0 can be a little bit difficult to wrap your head around when you first look at it, the aim of this library to encapsulate a lot of that confusion and provide a simple interface for making OAuth 1.0 calls. The OAuth 1.0 RFC was the standard that was kept in mind when building this library, though I feel that I should point out, not every service that calls itself an OAuth 1.0 service follows this standard.

This library works best with APIs that make an attempt to closely adhere to the Signature standards in the OAuth 1.0 specification, which unfortunately means that this may not work with every API that calls itself an OAuth 1.0. That doesn't mean that we've given up on those completely, it just means that as we become aware of them we'll have to analyze whether or not it's in the best interest of this project to accommodate various divergences from the OAuth 1.0 standard. Pull Requests are always welcome.

snaggle's People

Contributors

mfrost503 avatar localheinz avatar jasonrhodes avatar

Stargazers

Matheus Marabesi avatar  avatar Erick Patrick avatar

Watchers

 avatar James Cloos avatar

snaggle's Issues

RSA-SHA1 Signature implementation

In an effort to be in line with the specification, I'd like an implementation of this signature type. I could envision this signature being used in an internal environment, so I think it's valid

Post Fields

So Twitter API does this really stupid thing, where it requires any post fields to be added to the base string for the signature generation. The encoding seems a little bit different than the rest of the string...I feel like I had this working at one point...however it's not working right now.

It looks like they get tacked onto the end of the base string, key sorted alphabetically and weirdly encrypted. I'm not sure how many OAuth 1 APIs share this same strategy, I don't believe I've seen any. It was an easy enough tack on, so could Twitter could be used with an otherwise spec compliant library. Seems superfluous and unnecessary and doesn't really add much security...but it is what it is I suppose.

Removing the mutators in the credential classes

Now that the values are also injected into the constructor, we're going to be moving toward the preference of using that instead the verbose mutator interface. This will be a breaking a change, and part of major version 1.0.0 release.

Change the Interface for Credentials

I'd like to move away from the accessor methods for the Credentials...which would probably eliminate that interface as well. They are essentially Value Objects - so I'll like to move to:

$consumer = new ConsumerCredentials('KEY', 'SECRET');

This could be introduced with the current interface by defaulting the values to an empty string...if the setters come out, this change would be breaking and be required to jump a major version - to 1.0.0

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.