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
13class Microsoft extends AbstractService
14{
15    const SCOPE_BASIC = 'wl.basic';
16    const SCOPE_OFFLINE = 'wl.offline_access';
17    const SCOPE_SIGNIN = 'wl.signin';
18    const SCOPE_BIRTHDAY = 'wl.birthday';
19    const SCOPE_CALENDARS = 'wl.calendars';
20    const SCOPE_CALENDARS_UPDATE = 'wl.calendars_update';
21    const SCOPE_CONTACTS_BIRTHDAY = 'wl.contacts_birthday';
22    const SCOPE_CONTACTS_CREATE = 'wl.contacts_create';
23    const SCOPE_CONTACTS_CALENDARS = 'wl.contacts_calendars';
24    const SCOPE_CONTACTS_PHOTOS = 'wl.contacts_photos';
25    const SCOPE_CONTACTS_SKYDRIVE = 'wl.contacts_skydrive';
26    const SCOPE_EMAILS = 'wl.emails';
27    const SCOPE_EVENTS_CREATE = 'wl.events_create';
28    const SCOPE_MESSENGER = 'wl.messenger';
29    const SCOPE_PHONE_NUMBERS = 'wl.phone_numbers';
30    const SCOPE_PHOTOS = 'wl.photos';
31    const SCOPE_POSTAL_ADDRESSES = 'wl.postal_addresses';
32    const SCOPE_SHARE = 'wl.share';
33    const SCOPE_SKYDRIVE = 'wl.skydrive';
34    const SCOPE_SKYDRIVE_UPDATE = 'wl.skydrive_update';
35    const SCOPE_WORK_PROFILE = 'wl.work_profile';
36    const SCOPE_APPLICATIONS = 'wl.applications';
37    const SCOPE_APPLICATIONS_CREATE = 'wl.applications_create';
38    const SCOPE_IMAP = 'wl.imap';
39
40    /**
41     * MS uses some magical not officialy supported scope to get even moar info like full emailaddresses.
42     * They agree that giving 3rd party apps access to 3rd party emailaddresses is a pretty lame thing to do so in all
43     * their wisdom they added this scope because fuck you that's why.
44     *
45     * https://github.com/Lusitanian/PHPoAuthLib/issues/214
46     * http://social.msdn.microsoft.com/Forums/live/en-US/c6dcb9ab-aed4-400a-99fb-5650c393a95d/how-retrieve-users-
47     *                                  contacts-email-address?forum=messengerconnect
48     *
49     * Considering this scope is not officially supported: use with care
50     */
51    const SCOPE_CONTACTS_EMAILS = 'wl.contacts_emails';
52
53    public function __construct(
54        CredentialsInterface $credentials,
55        ClientInterface $httpClient,
56        TokenStorageInterface $storage,
57        $scopes = array(),
58        UriInterface $baseApiUri = null
59    ) {
60        parent::__construct($credentials, $httpClient, $storage, $scopes, $baseApiUri);
61
62        if (null === $baseApiUri) {
63            $this->baseApiUri = new Uri('https://apis.live.net/v5.0/');
64        }
65    }
66
67    /**
68     * {@inheritdoc}
69     */
70    public function getAuthorizationEndpoint()
71    {
72        return new Uri('https://login.live.com/oauth20_authorize.srf');
73    }
74
75    /**
76     * {@inheritdoc}
77     */
78    public function getAccessTokenEndpoint()
79    {
80        return new Uri('https://login.live.com/oauth20_token.srf');
81    }
82
83    /**
84     * {@inheritdoc}
85     */
86    public function getAuthorizationMethod()
87    {
88        return static::AUTHORIZATION_METHOD_QUERY_STRING;
89    }
90
91    /**
92     * {@inheritdoc}
93     */
94    protected function parseAccessTokenResponse($responseBody)
95    {
96        $data = json_decode($responseBody, true);
97
98        if (null === $data || !is_array($data)) {
99            throw new TokenResponseException('Unable to parse response.');
100        } elseif (isset($data['error'])) {
101            throw new TokenResponseException('Error in retrieving token: "' . $data['error'] . '"');
102        }
103
104        $token = new StdOAuth2Token();
105        $token->setAccessToken($data['access_token']);
106        $token->setLifetime($data['expires_in']);
107
108        if (isset($data['refresh_token'])) {
109            $token->setRefreshToken($data['refresh_token']);
110            unset($data['refresh_token']);
111        }
112
113        unset($data['access_token']);
114        unset($data['expires_in']);
115
116        $token->setExtraParams($data);
117
118        return $token;
119    }
120}
121