1<?php
2
3namespace OAuth\OAuth2\Service;
4
5use OAuth\OAuth2\Token\StdOAuth2Token;
6use OAuth\Common\Http\Exception\TokenResponseException;
7use OAuth\Common\Http\Uri\Uri;
8use OAuth\Common\Consumer\CredentialsInterface;
9use OAuth\Common\Http\Client\ClientInterface;
10use OAuth\Common\Storage\TokenStorageInterface;
11use OAuth\Common\Http\Uri\UriInterface;
12
13/**
14 * Heroku service.
15 *
16 * @author Thomas Welton <thomaswelton@me.com>
17 * @link https://devcenter.heroku.com/articles/oauth
18 */
19class Heroku extends AbstractService
20{
21    /**
22     * Defined scopes
23     * @link https://devcenter.heroku.com/articles/oauth#scopes
24     */
25    const SCOPE_GLOBAL          = 'global';
26    const SCOPE_IDENTITY        = 'identity';
27    const SCOPE_READ            = 'read';
28    const SCOPE_WRITE           = 'write';
29    const SCOPE_READ_PROTECTED  = 'read-protected';
30    const SCOPE_WRITE_PROTECTED = 'write-protected';
31
32    /**
33    * {@inheritdoc}
34    */
35    public function __construct(
36        CredentialsInterface $credentials,
37        ClientInterface $httpClient,
38        TokenStorageInterface $storage,
39        $scopes = array(),
40        UriInterface $baseApiUri = null
41    ) {
42        parent::__construct($credentials, $httpClient, $storage, $scopes, $baseApiUri);
43
44        if (null === $baseApiUri) {
45            $this->baseApiUri = new Uri('https://api.heroku.com/');
46        }
47    }
48
49    /**
50     * {@inheritdoc}
51     */
52    public function getAuthorizationEndpoint()
53    {
54        return new Uri('https://id.heroku.com/oauth/authorize');
55    }
56
57    /**
58     * {@inheritdoc}
59     */
60    public function getAccessTokenEndpoint()
61    {
62        return new Uri('https://id.heroku.com/oauth/token');
63    }
64
65    /**
66     * {@inheritdoc}
67     */
68    protected function getAuthorizationMethod()
69    {
70        return static::AUTHORIZATION_METHOD_HEADER_BEARER;
71    }
72
73    /**
74     * {@inheritdoc}
75     */
76    protected function parseAccessTokenResponse($responseBody)
77    {
78        $data = json_decode($responseBody, true);
79
80        if (null === $data || !is_array($data)) {
81            throw new TokenResponseException('Unable to parse response.');
82        } elseif (isset($data['error_description']) || isset($data['error'])) {
83            throw new TokenResponseException(
84                sprintf(
85                    'Error in retrieving token: "%s"',
86                    isset($data['error_description']) ? $data['error_description'] : $data['error']
87                )
88            );
89        }
90
91        $token = new StdOAuth2Token();
92        $token->setAccessToken($data['access_token']);
93        $token->setLifeTime($data['expires_in']);
94
95        if (isset($data['refresh_token'])) {
96            $token->setRefreshToken($data['refresh_token']);
97            unset($data['refresh_token']);
98        }
99
100        unset($data['access_token']);
101        unset($data['expires_in']);
102
103        $token->setExtraParams($data);
104
105        return $token;
106    }
107
108    /**
109     * {@inheritdoc}
110     */
111    protected function getExtraOAuthHeaders()
112    {
113        return array('Accept' => 'application/vnd.heroku+json; version=3');
114    }
115
116    /**
117     * {@inheritdoc}
118     */
119    protected function getExtraApiHeaders()
120    {
121        return array('Accept' => 'application/vnd.heroku+json; version=3', 'Content-Type' => 'application/json');
122    }
123}
124