Commits

Stan Lemon committed 475271a

PHP OAuth Example against Atlassian's Jira, also applicable for other Atlassian tools too

Comments (1)

Files changed (11)

-.DS_Store
+.DS_Store
+php/vendor/
+vendor
+Copyright (c) 2013 Stan Lemon
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+# Atlassian PHP OAuth Example
+This is an example of connecting with Atlassian Jira's OAuth service, thus allowing you to use their REST api. This example is built with Silex and Twig and uses the Guzzle library for OAuth and subsequent REST requests.  All of these tools can be easily installed with  [Composer](http://getcomposer.org), which can be installed using:
+
+	curl -s https://getcomposer.org/installer | php
+	
+Once you have composer, simply run the following inside of the source directory:
+
+	composer.phar install
+
+Next you will need to generate a private/public key and setup an Application Link inside of Jira.  You can generate the private/public key by running the following from your command line:
+
+	openssl req -x509 -nodes -days 365 -newkey rsa:1024 -sha1 -subj '/C=US/ST=CA/L=Mountain View/CN=www.example.com' -keyout ~/myrsakey.pem -out ~/myrsacert.pem
+
+Next you'll want to setup your application link inside of Jira, you can find instructions for that [here](https://confluence.atlassian.com/display/JIRA/Configuring+OAuth+Authentication+for+an+Application+Link).
+
+*Note: you'll be dealing with the incoming authentication and the public key you generated above will need to be pasted into the OAuth window.*
+
+Next up we need to make some changes to the config to point to your Jira instance, specifically these three lines:
+
+	$oauth = new Lemon\OAuth('http://localhost:8181/');
+	$oauth->setPrivateKey('/Users/stan/Sites/ssl/myrsakey.pem')
+	      ->setConsumerKey('1234567890')
+
+In the first line you'll want to change this to your Jira install.
+In the second line you'll want to change this to the path of your private key
+In the third line you'll want to put whatever you labeled as your *"consumer key"*.
+
+Once you've completed these changes point your web browser to the 'web' folder and click to authenticate with Jira.
+{
+    "name": "stanlemon/atlassian-oauth",
+    "description": "Atlassian PHP OAuth Example",
+    "keywords": ["atlassian", "jira", "oauth", "guzzle"],
+    "license": "MIT",
+    "autoload": {
+        "psr-0": { 
+            "": "src/"
+         }
+    },
+    "minimum-stability": "dev",
+    "require": {
+        "guzzle/guzzle": "3.0.*",
+        "silex/silex": "1.0.*",
+        "twig/twig": "1.*"
+    }
+}
+{
+    "hash": "0b5e48568d9cb814a0cd5eaa34da20ea",
+    "packages": [
+        {
+            "name": "guzzle/guzzle",
+            "version": "v3.0.7",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/guzzle/guzzle",
+                "reference": "v3.0.7"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://github.com/guzzle/guzzle/archive/v3.0.7.zip",
+                "reference": "v3.0.7",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.2",
+                "ext-curl": "*",
+                "symfony/event-dispatcher": ">=2.1"
+            },
+            "replace": {
+                "guzzle/batch": "self.version",
+                "guzzle/cache": "self.version",
+                "guzzle/common": "self.version",
+                "guzzle/http": "self.version",
+                "guzzle/inflection": "self.version",
+                "guzzle/iterator": "self.version",
+                "guzzle/log": "self.version",
+                "guzzle/parser": "self.version",
+                "guzzle/plugin": "self.version",
+                "guzzle/plugin-async": "self.version",
+                "guzzle/plugin-backoff": "self.version",
+                "guzzle/plugin-cache": "self.version",
+                "guzzle/plugin-cookie": "self.version",
+                "guzzle/plugin-curlauth": "self.version",
+                "guzzle/plugin-history": "self.version",
+                "guzzle/plugin-log": "self.version",
+                "guzzle/plugin-md5": "self.version",
+                "guzzle/plugin-mock": "self.version",
+                "guzzle/plugin-oauth": "self.version",
+                "guzzle/service": "self.version",
+                "guzzle/stream": "self.version"
+            },
+            "require-dev": {
+                "doctrine/common": "*",
+                "symfony/class-loader": "*",
+                "monolog/monolog": "1.*",
+                "zendframework/zend-cache": "2.0.*",
+                "zendframework/zend-log": "2.0.*",
+                "zend/zend-log1": "1.12",
+                "zend/zend-cache1": "1.12",
+                "phpunit/phpunit": "3.7.*"
+            },
+            "time": "2012-12-19 23:06:35",
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.0-dev"
+                }
+            },
+            "autoload": {
+                "psr-0": {
+                    "Guzzle\\Tests": "tests/",
+                    "Guzzle": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Michael Dowling",
+                    "email": "mtdowling@gmail.com",
+                    "homepage": "https://github.com/mtdowling"
+                },
+                {
+                    "name": "Guzzle Community",
+                    "homepage": "https://github.com/guzzle/guzzle/contributors"
+                }
+            ],
+            "description": "Guzzle is a PHP HTTP client library and framework for building RESTful web service clients",
+            "homepage": "http://guzzlephp.org/",
+            "keywords": [
+                "framework",
+                "curl",
+                "http",
+                "rest",
+                "http client",
+                "client",
+                "web service"
+            ]
+        },
+        {
+            "name": "pimple/pimple",
+            "version": "dev-master",
+            "source": {
+                "type": "git",
+                "url": "git://github.com/fabpot/Pimple.git",
+                "reference": "d58cec632dfdd3305d6b4f2563a5cf2a75b4d978"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://github.com/fabpot/Pimple/archive/d58cec632dfdd3305d6b4f2563a5cf2a75b4d978.zip",
+                "reference": "d58cec632dfdd3305d6b4f2563a5cf2a75b4d978",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.0"
+            },
+            "time": "2013-01-07 10:39:26",
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-0": {
+                    "Pimple": "lib/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                }
+            ],
+            "description": "Pimple is a simple Dependency Injection Container for PHP 5.3",
+            "homepage": "http://pimple.sensiolabs.org",
+            "keywords": [
+                "dependency injection",
+                "container"
+            ]
+        },
+        {
+            "name": "psr/log",
+            "version": "1.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-fig/log",
+                "reference": "1.0.0"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://github.com/php-fig/log/archive/1.0.0.zip",
+                "reference": "1.0.0",
+                "shasum": ""
+            },
+            "time": "2012-12-21 11:40:51",
+            "type": "library",
+            "autoload": {
+                "psr-0": {
+                    "Psr\\Log\\": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "PHP-FIG",
+                    "homepage": "http://www.php-fig.org/"
+                }
+            ],
+            "description": "Common interface for logging libraries",
+            "keywords": [
+                "log",
+                "psr",
+                "psr-3"
+            ]
+        },
+        {
+            "name": "silex/silex",
+            "version": "dev-master",
+            "source": {
+                "type": "git",
+                "url": "git://github.com/fabpot/Silex.git",
+                "reference": "86b9a18de51e289d930cdce7f88a8aedb4053911"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://github.com/fabpot/Silex/archive/86b9a18de51e289d930cdce7f88a8aedb4053911.zip",
+                "reference": "86b9a18de51e289d930cdce7f88a8aedb4053911",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3",
+                "pimple/pimple": "1.*",
+                "symfony/event-dispatcher": ">=2.1,<2.3-dev",
+                "symfony/http-foundation": ">=2.1,<2.3-dev",
+                "symfony/http-kernel": ">=2.1,<2.3-dev",
+                "symfony/routing": ">=2.1,<2.3-dev"
+            },
+            "require-dev": {
+                "monolog/monolog": ">=1.0.0,<1.2-dev",
+                "twig/twig": ">=1.8.0,<2.0-dev",
+                "swiftmailer/swiftmailer": "4.2.*",
+                "doctrine/dbal": ">=2.2.0,<2.4.0-dev",
+                "symfony/security": ">=2.1,<2.3-dev",
+                "symfony/config": ">=2.1,<2.3-dev",
+                "symfony/locale": ">=2.1,<2.3-dev",
+                "symfony/form": ">=2.1,<2.3-dev",
+                "symfony/browser-kit": ">=2.1,<2.3-dev",
+                "symfony/css-selector": ">=2.1,<2.3-dev",
+                "symfony/finder": ">=2.1,<2.3-dev",
+                "symfony/monolog-bridge": ">=2.1,<2.3-dev",
+                "symfony/process": ">=2.1,<2.3-dev",
+                "symfony/translation": ">=2.1,<2.3-dev",
+                "symfony/twig-bridge": ">=2.1,<2.3-dev",
+                "symfony/validator": ">=2.1,<2.3-dev",
+                "symfony/serializer": ">=2.1,<2.3-dev"
+            },
+            "suggest": {
+                "symfony/browser-kit": ">=2.1,<2.3-dev",
+                "symfony/css-selector": ">=2.1,<2.3-dev",
+                "symfony/dom-crawler": ">=2.1,<2.3-dev"
+            },
+            "time": "2013-01-19 14:44:48",
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-0": {
+                    "Silex": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Igor Wiedler",
+                    "email": "igor@wiedler.ch",
+                    "homepage": "http://wiedler.ch/igor/"
+                }
+            ],
+            "description": "The PHP micro-framework based on the Symfony2 Components",
+            "homepage": "http://silex.sensiolabs.org",
+            "keywords": [
+                "microframework"
+            ]
+        },
+        {
+            "name": "symfony/event-dispatcher",
+            "version": "dev-master",
+            "target-dir": "Symfony/Component/EventDispatcher",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/EventDispatcher",
+                "reference": "1ba2e333b644ac0a0e5ef751d514dd01b3a26e9d"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://github.com/symfony/EventDispatcher/archive/1ba2e333b644ac0a0e5ef751d514dd01b3a26e9d.zip",
+                "reference": "1ba2e333b644ac0a0e5ef751d514dd01b3a26e9d",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3"
+            },
+            "require-dev": {
+                "symfony/dependency-injection": "2.2.*"
+            },
+            "suggest": {
+                "symfony/dependency-injection": "2.2.*",
+                "symfony/http-kernel": "2.2.*"
+            },
+            "time": "2013-01-17 15:25:59",
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.2-dev"
+                }
+            },
+            "autoload": {
+                "psr-0": {
+                    "Symfony\\Component\\EventDispatcher\\": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "http://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony EventDispatcher Component",
+            "homepage": "http://symfony.com"
+        },
+        {
+            "name": "symfony/http-foundation",
+            "version": "dev-master",
+            "target-dir": "Symfony/Component/HttpFoundation",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/HttpFoundation",
+                "reference": "237e596d9dbeccd1f19e3b5ee06418c0e6000b21"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://github.com/symfony/HttpFoundation/archive/237e596d9dbeccd1f19e3b5ee06418c0e6000b21.zip",
+                "reference": "237e596d9dbeccd1f19e3b5ee06418c0e6000b21",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3"
+            },
+            "time": "2013-01-17 15:25:59",
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.2-dev"
+                }
+            },
+            "autoload": {
+                "psr-0": {
+                    "Symfony\\Component\\HttpFoundation\\": ""
+                },
+                "classmap": [
+                    "Symfony/Component/HttpFoundation/Resources/stubs"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "http://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony HttpFoundation Component",
+            "homepage": "http://symfony.com"
+        },
+        {
+            "name": "symfony/http-kernel",
+            "version": "dev-master",
+            "target-dir": "Symfony/Component/HttpKernel",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/HttpKernel",
+                "reference": "c5f232173a8f64d48117692eb029ef9e55e6d0f3"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://github.com/symfony/HttpKernel/archive/c5f232173a8f64d48117692eb029ef9e55e6d0f3.zip",
+                "reference": "c5f232173a8f64d48117692eb029ef9e55e6d0f3",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3",
+                "symfony/event-dispatcher": "2.2.*",
+                "symfony/http-foundation": "2.2.*",
+                "psr/log": ">=1.0,<2.0"
+            },
+            "require-dev": {
+                "symfony/browser-kit": "2.2.*",
+                "symfony/class-loader": "2.2.*",
+                "symfony/config": "2.2.*",
+                "symfony/console": "2.2.*",
+                "symfony/dependency-injection": "2.2.*",
+                "symfony/finder": "2.2.*",
+                "symfony/process": "2.2.*",
+                "symfony/routing": "2.2.*",
+                "symfony/stopwatch": "2.2.*"
+            },
+            "suggest": {
+                "symfony/browser-kit": "2.2.*",
+                "symfony/class-loader": "2.2.*",
+                "symfony/config": "2.2.*",
+                "symfony/console": "2.2.*",
+                "symfony/dependency-injection": "2.2.*",
+                "symfony/finder": "2.2.*"
+            },
+            "time": "2013-01-18 20:37:54",
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.2-dev"
+                }
+            },
+            "autoload": {
+                "psr-0": {
+                    "Symfony\\Component\\HttpKernel\\": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "http://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony HttpKernel Component",
+            "homepage": "http://symfony.com"
+        },
+        {
+            "name": "symfony/routing",
+            "version": "dev-master",
+            "target-dir": "Symfony/Component/Routing",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/Routing",
+                "reference": "9ce05861fd9aa6cbb14759a78ab30d07afcf489f"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://github.com/symfony/Routing/archive/9ce05861fd9aa6cbb14759a78ab30d07afcf489f.zip",
+                "reference": "9ce05861fd9aa6cbb14759a78ab30d07afcf489f",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3"
+            },
+            "require-dev": {
+                "doctrine/common": ">=2.2,<2.4-dev",
+                "symfony/config": "2.2.*",
+                "symfony/yaml": "2.2.*",
+                "symfony/http-kernel": "2.2.*",
+                "psr/log": ">=1.0,<2.0"
+            },
+            "suggest": {
+                "doctrine/common": ">=2.2,<2.4-dev",
+                "symfony/config": "2.2.*",
+                "symfony/yaml": "2.2.*"
+            },
+            "time": "2013-01-17 15:25:59",
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.2-dev"
+                }
+            },
+            "autoload": {
+                "psr-0": {
+                    "Symfony\\Component\\Routing\\": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "http://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony Routing Component",
+            "homepage": "http://symfony.com"
+        },
+        {
+            "name": "twig/twig",
+            "version": "dev-master",
+            "source": {
+                "type": "git",
+                "url": "git://github.com/fabpot/Twig.git",
+                "reference": "93c6a8dedc46c73ccdd61342de3d5e761e4412f6"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://github.com/fabpot/Twig/archive/93c6a8dedc46c73ccdd61342de3d5e761e4412f6.zip",
+                "reference": "93c6a8dedc46c73ccdd61342de3d5e761e4412f6",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.2.4"
+            },
+            "time": "2013-01-18 09:58:04",
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.12-dev"
+                }
+            },
+            "autoload": {
+                "psr-0": {
+                    "Twig_": "lib/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Armin Ronacher",
+                    "email": "armin.ronacher@active-4.com"
+                }
+            ],
+            "description": "Twig, the flexible, fast, and secure template language for PHP",
+            "homepage": "http://twig.sensiolabs.org",
+            "keywords": [
+                "templating"
+            ]
+        }
+    ],
+    "packages-dev": null,
+    "aliases": [
+
+    ],
+    "minimum-stability": "dev",
+    "stability-flags": [
+
+    ]
+}

php/src/Atlassian/OAuthWrapper.php

+<?php
+namespace Atlassian;
+
+use Guzzle\Http\Client;
+use Guzzle\Plugin\Oauth\OauthPlugin;
+
+class OAuthWrapper {
+
+	protected $baseUrl;
+	protected $sandbox;
+	protected $consumerKey;
+	protected $consumerSecret;
+	protected $callbackUrl;
+	protected $requestTokenUrl = 'oauth';
+	protected $accessTokenUrl = 'oauth';
+	protected $authorizationUrl = 'OAuth.action?oauth_token=%s';
+
+	protected $tokens;
+
+	protected $client;
+	protected $oauthPlugin;
+
+	public function __construct($baseUrl) {
+		$this->baseUrl = $baseUrl;
+	}
+
+	public function requestTempCredentials() {
+		return $this->requestCredentials(
+			$this->requestTokenUrl . '?oauth_callback=' . $this->callbackUrl	
+		);
+	}
+	
+	public function requestAuthCredentials($token, $tokenSecret, $verifier) {
+		return $this->requestCredentials(
+			$this->accessTokenUrl . '?oauth_callback=' . $this->callbackUrl . '&oauth_verifier=' . $verifier,
+			$token,
+			$tokenSecret
+		);
+	}
+
+	protected function requestCredentials($url, $token = false, $tokenSecret = false) {
+		$client = $this->getClient($token, $tokenSecret);
+
+		$response = $client->post($url)->send();
+
+		return $this->makeTokens($response);
+	}
+
+	protected function makeTokens($response) {
+		$body = (string) $response->getBody();
+
+		$tokens = array();
+		parse_str($body, $tokens);
+
+		if (empty($tokens)) {
+			throw new Exception("An error occurred while requesting oauth token credentials");
+		}
+
+		$this->tokens = $tokens;
+		return $this->tokens;
+	}
+
+	public function getClient($token = false, $tokenSecret = false) {
+		if (!is_null($this->client)) {
+			return $this->client;
+		} else {
+			$this->client = new Client($this->baseUrl);
+
+			$this->oauthPlugin = new OauthPlugin(array(
+				'consumer_key' 		=> $this->consumerKey,
+				'consumer_secret' 	=> $this->consumerSecret,
+				'token' 			=> !$token ? $this->tokens['oauth_token'] : $token,
+				'token_secret' 		=> !$token ? $this->tokens['oauth_token_secret'] : $tokenSecret,
+	            'signature_method' => 'RSA-SHA1',
+	            'signature_callback' => function($stringToSign, $key) {
+					if (!file_exists($this->privateKey)) {
+						throw new \InvalidArgumentException("Private key {$this->privateKey} does not exist");
+					}
+
+					$certificate = openssl_pkey_get_private('file://' . $this->privateKey);
+
+					$privateKeyId = openssl_get_privatekey($certificate);
+
+					$signature = null;
+
+					openssl_sign($stringToSign, $signature, $privateKeyId);
+					openssl_free_key($privateKeyId);
+
+					return $signature;
+	            }
+			));
+
+			$this->client->addSubscriber($this->oauthPlugin);
+
+			return $this->client;
+		}
+	}
+
+	public function makeAuthUrl() {
+		return $this->baseUrl . sprintf($this->authorizationUrl, urlencode($this->tokens['oauth_token']));
+	}
+
+	public function setConsumerKey($consumerKey) {
+		$this->consumerKey = $consumerKey;
+		return $this;
+	}
+
+	public function setConsumerSecret($consumerSecret) {
+		$this->consumerSecret = $consumerSecret;
+		return $this;
+	}
+
+	public function setCallbackUrl($callbackUrl) {
+		$this->callbackUrl = $callbackUrl;
+		return $this;
+	}
+
+	public function setRequestTokenUrl($requestTokenUrl) {
+		$this->requestTokenUrl = $requestTokenUrl;
+		return $this;
+	}
+
+	public function setAccessTokenUrl($accessTokenUrl) {
+		$this->accessTokenUrl = $accessTokenUrl;
+		return $this;
+	}
+
+	public function setAuthorizationUrl($authorizationUrl) {
+		$this->authorizationUrl = $authorizationUrl;
+		return $this;
+	}
+	
+	public function setPrivateKey($privateKey) {
+		$this->privateKey = $privateKey;
+		return $this;
+	}
+}

php/vendor/.hgkeep

Empty file added.

php/views/layout.twig

+<!DOCTYPE html>
+<html>
+	<head>
+		<meta charset="utf-8">
+		<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+		<title>Atlassian PHP OAuth Example</title>
+		<meta name="description" content="">
+		<meta name="viewport" content="width=device-width">
+		<style>body { padding-top: 60px; }</style>
+		<link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.2.1/css/bootstrap-combined.min.css" rel="stylesheet">
+	</head>
+	<body>
+		<div class="navbar navbar-inverse navbar-fixed-top">
+			<div class="navbar-inner">
+				<div class="container">
+					<a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
+						<span class="icon-bar"></span>
+						<span class="icon-bar"></span>
+						<span class="icon-bar"></span>
+					</a>
+
+					<a class="brand" href="#">Atlassian</a>
+					<div class="nav-collapse collapse">
+						<ul class="nav">
+							<li class="active"><a href="#">Home</a></li>
+					 	</ul>
+					</div>
+				</div>
+			</div>
+		</div>
+		<div class="container">
+
+		<h1>Atlassian PHP OAuth Example</h1>
+
+		<p><a href="{{app.url_generator.generate('reset')}}">Click here to reset the session.</a></p>
+
+		<p><a href="{{app.url_generator.generate('connect')}}">Click here to authenticate with Jira</a></p>
+
+		{% if oauth is not empty %}
+			<br />
+
+			<h3>OAuth Credentials</h3>
+			<table class="table table-striped">
+			{% for key, value in oauth %}
+				<tr>
+					<td>{{key}}</td>
+					<td>{{value}}</td>
+				</tr>
+			{% endfor %}
+			</table>
+		{% endif %}
+		
+		{% if priorities is not empty %}
+			<br />
+
+			<h3>Jira Priorities</h3>
+			<table class="table table-striped">
+			{% for priority in priorities %}
+				<tr>
+					<td>{{priority.id}}</td>
+					<td>{{priority.name}}</td>
+					<td>{{priority.description}}</td>
+				</tr>
+			{% endfor %}
+			</table>
+		{% endif %}
+	</body>
+</html>
+<IfModule mod_rewrite.c>
+    RewriteEngine On
+
+    #<IfModule mod_vhost_alias.c>
+    #    RewriteBase /
+    #</IfModule>
+
+    RewriteCond %{REQUEST_FILENAME} !-f
+    RewriteCond %{REQUEST_FILENAME} !-d
+    RewriteRule ^(.*)$ index.php [QSA,L]
+</IfModule>
+<?php
+require_once __DIR__ . '/../vendor/autoload.php';
+
+$app = new Silex\Application();
+$app['debug'] = true;
+$app->register(new Silex\Provider\TwigServiceProvider(), array(
+	'twig.path' => __DIR__ . '/../views',
+));
+$app->register(new Silex\Provider\SessionServiceProvider());
+$app->register(new Silex\Provider\UrlGeneratorServiceProvider());
+
+$app['oauth'] = $app->share(function() use($app){
+	$oauth = new Atlassian\OAuthWrapper('http://localhost:8181/');
+	$oauth->setPrivateKey('/Users/stan/Sites/ssl/myrsakey.pem')
+          ->setConsumerKey('1234567890')
+	      ->setConsumerSecret('')
+	      ->setRequestTokenUrl('plugins/servlet/oauth/request-token')
+	      ->setAuthorizationUrl('plugins/servlet/oauth/authorize?oauth_token=%s')
+	      ->setAccessTokenUrl('plugins/servlet/oauth/access-token')
+	      ->setCallbackUrl(
+              $app['url_generator']->generate('callback', array(), true)
+          );
+	;
+	return $oauth;
+});
+
+$app->get('/', function() use($app){
+	$oauth = $app['session']->get('oauth');
+
+	if (empty($oauth)) {
+		$priorities = null;
+	} else {
+		$priorities = $app['oauth']->getClient(
+			$oauth['oauth_token'], 
+			$oauth['oauth_token_secret']
+		)->get('rest/api/2/priority')->send()->json();
+	}
+
+	return $app['twig']->render('layout.twig', array(
+		'oauth' => $oauth,
+		'priorities' => $priorities,
+	));
+})->bind('home');
+
+$app->get('/connect', function() use($app){
+	$token = $app['oauth']->requestTempCredentials();
+	
+	$app['session']->set('oauth', $token);
+
+	return $app->redirect(
+		$app['oauth']->makeAuthUrl()
+	);
+})->bind('connect');
+
+$app->get('/callback', function() use($app){
+	$verifier = $app['request']->get('oauth_verifier');
+
+	if (empty($verifier)) {
+		throw new \InvalidArgumentException("There was no oauth verifier in the request");
+	}
+	
+	$tempToken = $app['session']->get('oauth');
+
+	$token = $app['oauth']->requestAuthCredentials(
+		$tempToken['oauth_token'],
+		$tempToken['oauth_token_secret'],
+		$verifier
+	);
+
+	$app['session']->set('oauth', $token);
+
+    return $app->redirect(
+		$app['url_generator']->generate('home')
+	);
+})->bind('callback');
+
+$app->get('/reset', function() use($app){
+	$app['session']->set('oauth', null);
+
+    return $app->redirect(
+		$app['url_generator']->generate('home')
+	);
+})->bind('reset');
+
+$app->run();