OAuth Authentication

Overview

AppDirect supports a wide variety of functionality through its API. These functions are invokable through standard HTTP methods: GET, POST, PUT, and DELETE. Each API calling URL must use standard REST conventions. Finally, all of AppDirect's APIs support "two-legged" OAuth 1.0, also known as "signed fetch." You will need to sign all calls to the API using "2-legged OAuth", meaning the authentication requests will be between the client/resource owner and the server.  You can read more about OAuth here, or refer to the OAuth Getting Started Guide available here.

OAuth authentication requires client credentials to authenticate the client when accessing information on the server. In order to use the AppDirect API, you must have access to the OAuth consumer key and consumer secret for your channel. (Channel admins are able to access this information.) All API calls must be signed with this key and secret. The OAuth consumer key and consumer secret can be found at https://appdirect.com/channel/integration, then scroll to the bottom of the screen. You must have channel administrator privileges to access this page.

Clicking the "Generate New Secret" generates a new OAuth consumer secret. AppDirect currently only supports OAuth HMAC-SHA1 signatures.

In the event of an error, the AppDirect APIs return an HTTP status code — such as 400 Bad Request or 409 Conflict — and a descriptive message. The status code and descriptive message are both readable in the JSON or XML response. Unauthenticated users and authenticated users with insufficient permissions see only 403 Forbidden.

Generating OAuth Requests

AppDirect's APIs support "two-legged" OAuth 1.0, also known as "signed fetch." Rather than obtaining OAuth access tokens, all requests include a signed OAuth request in the Authorization header using the credentials dsecribed above. The example below shows getting a list of orders for an OAuth consumer "Dummy" using the developer key (that is, the OAuth consumer secret) value "secret".

Note that the Authorization header should be contained on a single line. Line breaks have been inserted here for clarity.


GET https://www.appdirect.com/api/billing/v1/orders HTTP/1.1
Host: www.appdirect.com
Content-Type: application/xml
Authorization: OAuth realm="",
oauth_nonce="72250409",
oauth_timestamp="1294966759",
oauth_consumer_key="Dummy",
oauth_signature_method="HMAC-SHA1",
oauth_version="1.0",
oauth_signature="IBlWhOm3PuDwaSdxE/Qu4RKPtVE="

This signature may also appear in a URL query parameter as follows:


https://www.appdirect.com/rest/api/events/orders?oauth_nonce=72250409&oauth_timestamp=1294966759&oauth_consumer_key=Dummy&oauth_signature_method=HMAC-SHA1&oauth_version=1.0&oauth_signature=IBlWhOm3PuDwaSdxE%2FQu4RKPtVE%3D

Validating Requests From AppDirect

All outgoing requests from AppDirect to a software vendor will be signed with that vendor's OAuth credentials. Vendors MUST verify these signatures to ensure that requests originate from AppDirect. This is important to note because several subscription and user-related API calls will trigger event notifications to be sent from AppDirect to the vendor. Non-interactive requests sent between AppDirect and the vendor will contain an OAuth signature in the Authorization header. Interactive requests, where the user is redirected to the vendor, will contain a signature in the URL parameters.

Signing Return URLs

With AppDirect's interactive callbacks, a user will be redirected to an application's website to complete some transaction (for example, a subscription order). After completing that transaction on the application side, the application will redirect the user back to AppDirect. To ensure that the redirect comes from the application, a two-legged OAuth signature will be applied to the redirect URL itself.

For example, suppose a SUBSCRIPTION_ORDER event were passed with redirect URL, sush as https://www.appdirect.com/finishorder.

Assuming the order is handled successfully and the parameters "success=true" and "accountIdentifier=Alice" were being returned (https://www.appdirect.com/finishorder?success=true&accountIdentifer=Alice), the application would need to sign the URL with the OAuth consumer key "Dummy" and secret "secret" as follows:


https://www.appdirect.com/finishorder?success=true&accountIdentifer=Alice&oauth_nonce=95009478&oauth_timestamp=1294967177&oauth_consumer_key=Dummy&oauth_signature_method=HMAC-SHA1&oauth_version=1.0&oauth_signature=sTmXIbI2QgUCroj9mIPBp6NPars%3D

OAuth API Code Examples

You may test your integration using the OAuth consumer key value "Dummy" and consumer secret value "secret." Open source OAuth implementations are available in several languages. The following examples will make a signed OAuth request to AppDirect.

Java

This example uses OAuth Signpost to sign an outgoing request.


OAuthConsumer consumer = new DefaultOAuthConsumer("Dummy", "secret");
URL url = new URL("https://www.appdirect.com/api/events/dummyChange");
HttpURLConnection request = (HttpURLConnection) url.openConnection();
consumer.sign(request);
request.connect();

This example signs a return URL as follows.


OAuthConsumer consumer = new DefaultOAuthConsumer("Dummy", "secret");
consumer.setSigningStrategy( new QueryStringSigningStrategy());
String url = "https://www.appdirect.com/AppDirect/finishorder?success=true&accountIdentifer=Alice";
String signedUrl = consumer.sign(url);

Python

This example uses the python-oauth2 client to sign and issue a request.


import oauth2 as oauth
consumer_key = 'Dummy'
consumer_secret = 'secret'
request_url = "https://www.appdirect.com/AppDirect/rest/api/events/dummyChange"

# Create your consumer with the proper key/secret.
consumer = oauth.Consumer(consumer_key, consumer_secret)

# Create our client.
client = oauth.Client(consumer)

# The OAuth Client request works just like httplib2 for the most part.
resp, content = client.request(request_url)
print resp
print content

This example signs a return URL as follows.


import oauth2 as oauth

consumer_key = 'Dummy'
consumer_secret = 'secret'
request_url = "https://www.appdirect.com/AppDirect/finishorder?success=true&accountIdentifer=Alice"
req = oauth.Request("GET", request_url)
# Python-oauth2 Request.sign() does not include a timestamp or nonce by default
req['oauth_timestamp'] = oauth.Request.make_timestamp()
req['oauth_nonce'] = oauth.Request.make_nonce()
sig_method = oauth.SignatureMethod_HMAC_SHA1()
consumer = oauth.Consumer(consumer_key, consumer_secret)
req.sign_request(sig_method, consumer, token=None)
print req.to_url()

PHP

This example uses Andy Smith's Basic OAuth Library. It also depends on Curl.


require_once('OAuth.php');

# Initialize OAuth Consumer
$CONSUMER_KEY = "Dummy";
$CONSUMER_SECRET = "secret";
$consumer = new OAuthConsumer($CONSUMER_KEY, $CONSUMER_SECRET);

# Prepare the request
$eventUrl = 'https://www.appdirect.com/api/events/dummyAssign';
$request = OAuthRequest::from_consumer_and_token($consumer, NULL, 'GET', $eventUrl, NULL);
$request->sign_request(new OAuthSignatureMethod_HMAC_SHA1(), $consumer, NULL);
$auth_header = $request->to_header();

# Setup curl
$curl = curl_init($eventUrl);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_FAILONERROR, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_HTTPHEADER, array($auth_header));

# Fetch the event
$response = curl_exec($curl);
curl_close($curl);

This example will generate a signed URL, appropriate for user redirects.


$request = OAuthRequest::from_consumer_and_token($consumer, NULL, 'GET', $eventUrl, NULL);
$request->sign_request(new OAuthSignatureMethod_HMAC_SHA1(), $consumer, NULL);
$url = $request->to_url();

This example will parse and display the response using simplexml.


$event = simplexml_load_string($response);
$account = $event->payload->account;
$assignedUser = $event->payload->user;
$creator = $event->creator;

Ruby

This code uses the oauth gem to sign and issue a request. It will also "pretty-print" the result using xml-simple.


require 'rubygems'
require 'oauth'
require 'xmlsimple'

event_url = "https://www.appdirect.com/api/events/dummyOrder"
consumer = OAuth::Consumer.new("Dummy", "secret")
access_token = OAuth::AccessToken.new(consumer)
response = access_token.get(event_url)
event = XmlSimple.xml_in(response.body)
output = XmlSimple.xml_out(event)
print output

This example will generate a signed URL.


require 'rubygems'
require 'oauth'

event_url = "https://www.appdirect.com/rest/api/events/dummyOrder"
site = "https://www.appdirect.com"
path = "/redirect/path"
consumer = OAuth::Consumer.new("Dummy", "secret", {
                               :site => site,
                               :scheme => :query_string })
req = consumer.create_signed_request(:get, path)
print "#{site}#{req.path}"

C#

This code will generate a signed URL and make a request to fetch the event using OAuthBase.


OAuthBase oauthBase = new OAuthBase();
string uri = "https://www.appdirect.com/api/events/dummyOrder";
string consumerKey = "Dummy";
string consumerSecret = "secret";
string timestamp = oauthBase.GenerateTimeStamp();
string nonce = oauthBase.GenerateNonce();
string normalizedUrl;
string normalizedRequestParameters;
string sig = HttpUtility.UrlEncode(oauthBase.GenerateSignature(
    new Uri(uri), consumerKey, consumerSecret, string.Empty, string.Empty,
    "GET", timestamp, nonce, out normalizedUrl, out normalizedRequestParameters));
string requestUrl = String.Format("{0}?{1}&oauth_signature={2}", normalizedUrl, normalizedRequestParameters, sig);
Console.WriteLine(requestUrl);

HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(requestUrl);
HttpWebResponse response = (HttpWebResponse) request.GetResponse();
Console.WriteLine(new StreamReader(response.GetResponseStream()).ReadToEnd());