Passed
Push — main ( 129f19...5ed128 )
by smiley
31:18
created

Twitch::getRequestAuthorization()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 3
c 0
b 0
f 0
dl 0
loc 4
rs 10
cc 1
nc 1
nop 2
1
<?php
2
/**
3
 * Class Twitch
4
 *
5
 * @link https://dev.twitch.tv/docs/api/reference/
6
 * @link https://dev.twitch.tv/docs/authentication/
7
 *
8
 * @created      22.10.2017
9
 * @author       Smiley <[email protected]>
10
 * @copyright    2017 Smiley
11
 * @license      MIT
12
 */
13
14
namespace chillerlan\OAuth\Providers\Twitch;
15
16
use chillerlan\OAuth\Core\{AccessToken, ClientCredentials, CSRFToken, OAuth2Provider, TokenRefresh};
17
use Psr\Http\Message\RequestInterface;
18
19
use function http_build_query, implode;
20
use const PHP_QUERY_RFC1738;
21
22
/**
23
 * @method \Psr\Http\Message\ResponseInterface analyticsExtensions(array $params = ['after', 'ended_at', 'extension_id', 'first', 'started_at', 'type'])
24
 * @method \Psr\Http\Message\ResponseInterface analyticsGames(array $params = ['after', 'ended_at', 'first', 'game_id', 'started_at', 'type'])
25
 * @method \Psr\Http\Message\ResponseInterface bitsCheermotes(array $params = ['broadcaster_id'])
26
 * @method \Psr\Http\Message\ResponseInterface bitsLeaderboard(array $params = ['count', 'period', 'started_at', 'user_id'])
27
 * @method \Psr\Http\Message\ResponseInterface channelPointsCustomRewards(array $params = ['broadcaster_id', 'id', 'only_manageable_rewards'])
28
 * @method \Psr\Http\Message\ResponseInterface channelPointsCustomRewardsCreate(array $params = ['broadcaster_id'], array $body = ['title', 'prompt', 'cost', 'is_enabled', 'background_color', 'is_user_input_required', 'is_max_per_stream_enabled', 'max_per_stream', 'is_max_per_user_per_stream_enabled', 'max_per_user_per_stream', 'is_global_cooldown_enabled', 'global_cooldown_seconds', 'should_redemptions_skip_request_queue'])
29
 * @method \Psr\Http\Message\ResponseInterface channelPointsCustomRewardsDelete(array $params = ['broadcaster_id', 'id'])
30
 * @method \Psr\Http\Message\ResponseInterface channelPointsCustomRewardsRedemptions(array $params = ['broadcaster_id', 'reward_id', 'id', 'status', 'sort', 'after', 'first'])
31
 * @method \Psr\Http\Message\ResponseInterface channelPointsCustomRewardsRedemptionsUpdate(array $params = ['id', 'broadcaster_id', 'reward_id'], array $body = ['status'])
32
 * @method \Psr\Http\Message\ResponseInterface channelPointsCustomRewardsUpdate(array $params = ['broadcaster_id', 'id'], array $body = ['title', 'prompt', 'cost', 'background_color', 'is_enabled', 'is_user_input_required', 'is_max_per_stream_enabled', 'max_per_stream', 'is_max_per_user_per_stream_enabled', 'max_per_user_per_stream', 'is_global_cooldown_enabled', 'global_cooldown_seconds', 'is_paused', 'should_redemptions_skip_request_queue'])
33
 * @method \Psr\Http\Message\ResponseInterface channels(array $params = ['broadcaster_id'])
34
 * @method \Psr\Http\Message\ResponseInterface channelsCommercial(array $body = ['broadcaster_id', 'length'])
35
 * @method \Psr\Http\Message\ResponseInterface channelsEditors(array $params = ['broadcaster_id'])
36
 * @method \Psr\Http\Message\ResponseInterface channelsUpdate(array $params = ['broadcaster_id'], array $body = ['game_id', 'broadcaster_language', 'title'])
37
 * @method \Psr\Http\Message\ResponseInterface clips(array $params = ['broadcaster_id', 'game_id', 'id', 'after', 'before', 'ended_at', 'first', 'started_at'])
38
 * @method \Psr\Http\Message\ResponseInterface clipsCreate(array $params = ['broadcaster_id', 'has_delay'])
39
 * @method \Psr\Http\Message\ResponseInterface entitlementsCodes(array $params = ['Param', 'code', 'user_id'])
40
 * @method \Psr\Http\Message\ResponseInterface entitlementsCodesCreate(array $params = ['code', 'user_id'])
41
 * @method \Psr\Http\Message\ResponseInterface entitlementsDrops(array $params = ['id', 'user_id', 'game_id', 'after', 'first'])
42
 * @method \Psr\Http\Message\ResponseInterface eventsubSubscriptions(array $params = ['status', 'type'])
43
 * @method \Psr\Http\Message\ResponseInterface eventsubSubscriptionsCreate(array $body = ['type', 'version', 'condition', 'transport'])
44
 * @method \Psr\Http\Message\ResponseInterface eventsubSubscriptionsDelete(array $params = ['id'])
45
 * @method \Psr\Http\Message\ResponseInterface extensionsTransactions(array $params = ['extension_id', 'id', 'after', 'first'])
46
 * @method \Psr\Http\Message\ResponseInterface games(array $params = ['id', 'name'])
47
 * @method \Psr\Http\Message\ResponseInterface gamesTop(array $params = ['after', 'before', 'first'])
48
 * @method \Psr\Http\Message\ResponseInterface hypetrainEvents(array $params = ['broadcaster_id', 'first', 'id', 'cursor'])
49
 * @method \Psr\Http\Message\ResponseInterface moderationBanned(array $params = ['broadcaster_id', 'user_id', 'first', 'after', 'before'])
50
 * @method \Psr\Http\Message\ResponseInterface moderationBannedEvents(array $params = ['broadcaster_id', 'user_id', 'after', 'first'])
51
 * @method \Psr\Http\Message\ResponseInterface moderationEnforcementsStatus(array $params = ['broadcaster_id'], array $body = ['msg_id', 'msg_text', 'user_id'])
52
 * @method \Psr\Http\Message\ResponseInterface moderationModerators(array $params = ['broadcaster_id', 'user_id', 'first', 'after'])
53
 * @method \Psr\Http\Message\ResponseInterface moderationModeratorsEvents(array $params = ['broadcaster_id', 'user_id', 'after', 'first'])
54
 * @method \Psr\Http\Message\ResponseInterface searchCategories(array $params = ['query', 'first', 'after'])
55
 * @method \Psr\Http\Message\ResponseInterface searchChannels(array $params = ['query', 'first', 'after', 'live_only'])
56
 * @method \Psr\Http\Message\ResponseInterface streams(array $params = ['after', 'before', 'first', 'game_id', 'language', 'user_id', 'user_login'])
57
 * @method \Psr\Http\Message\ResponseInterface streamsKey(array $params = ['broadcaster_id'])
58
 * @method \Psr\Http\Message\ResponseInterface streamsMarkers(array $params = ['user_id', 'video_id', 'after', 'before', 'first'])
59
 * @method \Psr\Http\Message\ResponseInterface streamsMarkersCreate(array $body = ['user_id', 'description'])
60
 * @method \Psr\Http\Message\ResponseInterface streamsTags(array $params = ['broadcaster_id'])
61
 * @method \Psr\Http\Message\ResponseInterface streamsTagsUpdate(array $params = ['broadcaster_id'], array $body = ['tag_ids'])
62
 * @method \Psr\Http\Message\ResponseInterface subscriptions(array $params = ['broadcaster_id', 'user_id', 'after', 'first'])
63
 * @method \Psr\Http\Message\ResponseInterface subscriptionsUser(array $params = ['broadcaster_id', 'user_id'])
64
 * @method \Psr\Http\Message\ResponseInterface tagsStreams(array $params = ['after', 'first', 'tag_id'])
65
 * @method \Psr\Http\Message\ResponseInterface teams(array $params = ['name', 'id'])
66
 * @method \Psr\Http\Message\ResponseInterface teamsChannel(array $params = ['broadcaster_id'])
67
 * @method \Psr\Http\Message\ResponseInterface users(array $params = ['id', 'login'])
68
 * @method \Psr\Http\Message\ResponseInterface usersBlocks(array $params = ['broadcaster_id', 'first', 'after'])
69
 * @method \Psr\Http\Message\ResponseInterface usersBlocksDelete(array $params = ['target_user_id'])
70
 * @method \Psr\Http\Message\ResponseInterface usersBlocksUpdate(array $params = ['target_user_id', 'source_context', 'reason'])
71
 * @method \Psr\Http\Message\ResponseInterface usersExtensions(array $params = ['user_id'])
72
 * @method \Psr\Http\Message\ResponseInterface usersExtensionsList()
73
 * @method \Psr\Http\Message\ResponseInterface usersExtensionsUpdate()
74
 * @method \Psr\Http\Message\ResponseInterface usersFollows()
75
 * @method \Psr\Http\Message\ResponseInterface usersFollowsCreate(array $params = ['from_id', 'to_id', 'allow_notifications'])
76
 * @method \Psr\Http\Message\ResponseInterface usersFollowsDelete(array $params = ['from_id', 'to_id'])
77
 * @method \Psr\Http\Message\ResponseInterface usersUpdate(array $params = ['description'])
78
 * @method \Psr\Http\Message\ResponseInterface videos(array $params = ['id', 'user_id', 'game_id', 'after', 'before', 'first', 'language', 'period', 'sort', 'type'])
79
 * @method \Psr\Http\Message\ResponseInterface videosDelete(array $params = ['id'])
80
 * @method \Psr\Http\Message\ResponseInterface webhooksSubscriptions(array $params = ['after', 'first'])
81
 */
82
class Twitch extends OAuth2Provider implements ClientCredentials, CSRFToken, TokenRefresh{
83
84
	public const SCOPE_ANALYTICS_READ_EXTENSIONS  = 'analytics:read:extensions';
85
	public const SCOPE_ANALYTICS_READ_GAMES       = 'analytics:read:games';
86
	public const SCOPE_BITS_READ                  = 'bits:read';
87
	public const SCOPE_CHANNEL_EDIT_COMMERCIAL    = 'channel:edit:commercial';
88
	public const SCOPE_CHANNEL_MANAGE_BROADCAST   = 'channel:manage:broadcast';
89
	public const SCOPE_CHANNEL_MANAGE_EXTENSIONS  = 'channel:manage:extensions';
90
	public const SCOPE_CHANNEL_MANAGE_REDEMPTIONS = 'channel:manage:redemptions';
91
	public const SCOPE_CHANNEL_MANAGE_VIDEOS      = 'channel:manage:videos';
92
	public const SCOPE_CHANNEL_READ_EDITORS       = 'channel:read:editors';
93
	public const SCOPE_CHANNEL_READ_HYPE_TRAIN    = 'channel:read:hype_train';
94
	public const SCOPE_CHANNEL_READ_REDEMPTIONS   = 'channel:read:redemptions';
95
	public const SCOPE_CHANNEL_READ_STREAM_KEY    = 'channel:read:stream_key';
96
	public const SCOPE_CHANNEL_READ_SUBSCRIPTIONS = 'channel:read:subscriptions';
97
	public const SCOPE_CLIPS_EDIT                 = 'clips:edit';
98
	public const SCOPE_MODERATION_READ            = 'moderation:read';
99
	public const SCOPE_USER_EDIT                  = 'user:edit';
100
	public const SCOPE_USER_EDIT_FOLLOWS          = 'user:edit:follows';
101
	public const SCOPE_USER_READ_BLOCKED_USERS    = 'user:read:blocked_users';
102
	public const SCOPE_USER_MANAGE_BLOCKED_USERS  = 'user:manage:blocked_users';
103
	public const SCOPE_USER_READ_BROADCAST        = 'user:read:broadcast';
104
	public const SCOPE_USER_READ_EMAIL            = 'user:read:email';
105
	public const SCOPE_USER_READ_SUBSCRIPTIONS    = 'user:read:subscriptions';
106
107
	protected string $authURL          = 'https://id.twitch.tv/oauth2/authorize';
108
	protected string $accessTokenURL   = 'https://id.twitch.tv/oauth2/token';
109
	protected ?string $apiURL          = 'https://api.twitch.tv';
110
	protected ?string $userRevokeURL   = 'https://www.twitch.tv/settings/connections';
111
	protected ?string $revokeURL       = 'https://id.twitch.tv/oauth2/revoke';
112
	protected ?string $endpointMap     = TwitchEndpoints::class;
113
	protected ?string $apiDocs         = 'https://dev.twitch.tv/docs/api/reference/';
114
	protected ?string $applicationURL  = 'https://dev.twitch.tv/console/apps/create';
115
	protected array $authHeaders       = ['Accept' => 'application/vnd.twitchtv.v5+json'];
116
	protected array $apiHeaders        = ['Accept' => 'application/vnd.twitchtv.v5+json'];
117
118
	protected array $defaultScopes     =  [
119
		self::SCOPE_USER_READ_EMAIL,
120
	];
121
122
	/**
123
	 * @link https://dev.twitch.tv/docs/authentication#oauth-client-credentials-flow-app-access-tokens
124
	 *
125
	 * @param array|null $scopes
126
	 *
127
	 * @return \chillerlan\OAuth\Core\AccessToken
128
	 */
129
	public function getClientCredentialsToken(array $scopes = null):AccessToken{
130
		$params = [
131
			'client_id'     => $this->options->key,
132
			'client_secret' => $this->options->secret,
133
			'grant_type'    => 'client_credentials',
134
		];
135
136
		if($scopes !== null){
137
			$params['scope'] = implode($this->scopesDelimiter, $scopes);
138
		}
139
140
		$request = $this->requestFactory
141
			->createRequest('POST', $this->clientCredentialsTokenURL ?? $this->accessTokenURL)
142
			->withHeader('Content-Type', 'application/x-www-form-urlencoded')
143
			->withBody($this->streamFactory->createStream(http_build_query($params, '', '&', PHP_QUERY_RFC1738)))
144
		;
145
146
		foreach($this->authHeaders as $header => $value){
147
			$request = $request->withAddedHeader($header, $value);
148
		}
149
150
		$token = $this->parseTokenResponse($this->http->sendRequest($request));
151
152
		$this->storage->storeAccessToken($this->serviceName, $token);
153
154
		return $token;
155
	}
156
157
	/**
158
	 * @inheritDoc
159
	 */
160
	public function getRequestAuthorization(RequestInterface $request, AccessToken $token):RequestInterface{
161
		return $request
162
			->withHeader('Authorization', $this->authMethodHeader.' '.$token->accessToken)
163
			->withHeader('Client-ID', $this->options->key);
164
	}
165
166
}
167