Skip to content

Commit 89fa0d1

Browse files
authored
Merge pull request #13 from Nekland/feature/follow-google-auth
Follow google auth
2 parents eda32f0 + 4d0ddfc commit 89fa0d1

13 files changed

+245
-70
lines changed

Diff for: .travis.yml

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
language: php
22

33
php:
4-
- 5.4
5-
- 5.5
64
- 5.6
75
- 7.0
86
- 7.1
7+
- 7.2
98

109

1110
branches:

Diff for: CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
55
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
66

77
## [Unreleased]
8+
### Added
9+
- New auth method because google given now different information than before
810

911
## [0.1.0] - 2017-06-20
1012
### Added

Diff for: Readme.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ $youtube = new Youtube();
2727

2828
// You have to authenticate to access the youtube api
2929
$youtube->authenticate(
30-
'ServiceAuth',
31-
['cert_file' => 'my_google_certificate', 'email' => 'myemail_for_google_service@googleapi_etc.com']
30+
'JsonFileServiceAuth',
31+
['json_file' => 'my_google_certificate.json']
3232
);
3333

3434
// The info variable will contains an array of data returned by google

Diff for: composer.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
}
1313
],
1414
"require": {
15-
"php": ">=5.4",
15+
"php": ">=5.6",
1616
"guzzle/guzzle": ">=3.7",
1717
"nekland/base-api": "~0.0.1",
1818
"namshi/jose": "~1.2"

Diff for: docs/authentication.md

+38-7
Original file line numberDiff line numberDiff line change
@@ -37,18 +37,49 @@ $youtube->authenticate(
3737
Service Account (via OAuth)
3838
----------------------------
3939

40+
To make this authentication work, you need to generate a JSON file from the google developer console.
41+
You can do it like that:
42+
43+
1. Go to [https://console.developers.google.com/apis/dashboard](https://console.developers.google.com/apis/dashboard)
44+
2. Create your project if it's not already in the project list (we do not care about the project id)
45+
3. Click on the name of your project in the list present on the top of the dashboard
46+
4. Enable Youtube API for this project
47+
5. Go to credentials page
48+
6. In the section `OAuth`, create a new Client ID of type `Service Account`
49+
7. Follow the link `Manage services accounts`
50+
51+
> This procedure can change since we do not decide of the google website UX :) .
52+
53+
Now you have your key file you can use `YoutubeApi` like that:
54+
55+
```php
56+
<?php
57+
58+
$youtube = new Youtube();
59+
$youtube->authenticate(
60+
'JsonFileServiceAuth',
61+
['json_file' => 'my_google_certificate.json']
62+
);
63+
```
64+
65+
66+
Service Account (via OAuth)
67+
----------------------------
68+
69+
_Note: if this method is still supported by the library as well as Google, this method is deprecated._
70+
4071
To make this authentication work, you need to generate a P12 key certificate and an API email from the google developer console.
4172
You can do it like that:
4273

43-
1. Go to [https://console.developers.google.com/project](https://console.developers.google.com/project);
44-
2. Create your project if it's not already in the project list (we do not care about the project id);
45-
3. Click on the name of your project in the list;
46-
4. Click on APIS & AUTH > API and on "YouTube Data API v3" in the API list and click on "OFF" button to make it becoming "ON";
47-
5. Click on APIs & AUTH > Credentials;
74+
1. Go to [https://console.developers.google.com/apis/dashboard](https://console.developers.google.com/apis/dashboard)
75+
2. Create your project if it's not already in the project list (we do not care about the project id)
76+
3. Click on the name of your project in the list present on the top of the dashboard
77+
4. Enable Youtube API for this project
78+
5. Go to credentials page
4879
6. In the section `OAuth`, create a new Client ID of type `Service Account`
49-
7. Click on "Generate new P12 key" to download your certificate key
80+
7. Follow the link `Manage services accounts`
5081

51-
> This procedure can change since we do not decide of the google website usability :) .
82+
> This procedure can change since we do not decide of the google website UX :) .
5283
5384
Now you have your key file you can use `YoutubeApi` like that:
5485

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?php
2+
3+
/**
4+
* This file is a part of nekland youtube api package
5+
*
6+
* (c) Nekland <[email protected]>
7+
*
8+
* For the full license, take a look to the LICENSE file
9+
* on the root directory of this project
10+
*/
11+
12+
namespace Nekland\YoutubeApi\Http\Auth;
13+
14+
/**
15+
* Class JsonfileServiceAuth
16+
*
17+
* Options:
18+
* json_file: the path to the json file given by Google
19+
*/
20+
final class JsonFileServiceAuth extends ServiceAuth
21+
{
22+
/**
23+
* @var array
24+
*/
25+
private $json;
26+
27+
/**
28+
* {@inheritdoc}
29+
*/
30+
protected function getIss()
31+
{
32+
$this->loadFile();
33+
34+
return $this->json['client_email'];
35+
}
36+
37+
/**
38+
* {@inheritdoc}
39+
*/
40+
protected function getPrivateKey()
41+
{
42+
$this->loadFile();
43+
44+
return $this->json['private_key'];
45+
46+
}
47+
48+
/**
49+
* @return array
50+
* @throws \Nekland\YoutubeApi\Exception\MissingOptionException if the required option is not set.
51+
*/
52+
private function loadFile()
53+
{
54+
if ($this->json) {
55+
return $this->json;
56+
}
57+
58+
$json = file_get_contents($this->getOption('json_file'));
59+
60+
return $this->json = json_decode($json, true);
61+
}
62+
}

Diff for: lib/Nekland/YoutubeApi/Http/Auth/ServiceAuth.php

+24-8
Original file line numberDiff line numberDiff line change
@@ -18,22 +18,30 @@
1818
use Nekland\YoutubeApi\Exception\AuthException;
1919
use Nekland\YoutubeApi\Exception\MissingOptionException;
2020

21+
/**
22+
* Class ServiceAuth
23+
*
24+
* Options:
25+
* email: google api service account
26+
* cert_file: path to the file that contain the certificate
27+
* cert_password: password to decrypt the (p12) certificate
28+
*/
2129
class ServiceAuth implements AuthInterface
2230
{
2331
/**
2432
* @var array
2533
*/
26-
private $options;
34+
protected $options;
2735

2836
/**
2937
* @var \Guzzle\Http\ClientInterface
3038
*/
31-
private $client;
39+
protected $client;
3240

3341
/**
3442
* @param \Guzzle\Http\ClientInterface $client
3543
*/
36-
public function __construct(\Guzzle\Http\ClientInterface $client=null)
44+
public function __construct(\Guzzle\Http\ClientInterface $client = null)
3745
{
3846
if (null === $client) {
3947
$this->client = new Client();
@@ -60,9 +68,9 @@ private function getToken()
6068
{
6169
$jws = new JWS('RS256');
6270
$jws->setPayload(array(
63-
'iss' => $this->getOption('email'),
71+
'iss' => $this->getIss(),
6472
'scope' => 'https://www.googleapis.com/auth/youtube',
65-
'aud' =>'https://accounts.google.com/o/oauth2/token',
73+
'aud' =>'https://www.googleapis.com/oauth2/v4/token',
6674
'exp' => time() + 60,
6775
'iat' => time()
6876
));
@@ -84,11 +92,19 @@ private function getToken()
8492
return $finalArray['access_token'];
8593
}
8694

95+
/**
96+
* @return string
97+
*/
98+
protected function getIss()
99+
{
100+
return $this->getOption('email');
101+
}
102+
87103
/**
88104
* @return string
89105
* @throws \Nekland\YoutubeApi\Exception\AuthException
90106
*/
91-
private function getPrivateKey()
107+
protected function getPrivateKey()
92108
{
93109
$file = $this->getOption('cert_file');
94110
$res = array();
@@ -100,7 +116,7 @@ private function getPrivateKey()
100116
return $res['pkey'];
101117
}
102118

103-
throw new AuthException(sprintf('The certificate "%" looks wrong PHP cannot open it.', $file));
119+
throw new AuthException(sprintf('The key to open the p12 "%" file looks wrong, or the file is malformed.', $file));
104120
}
105121

106122
/**
@@ -109,7 +125,7 @@ private function getPrivateKey()
109125
* @return mixed
110126
* @throws \Nekland\YoutubeApi\Exception\MissingOptionException
111127
*/
112-
private function getOption($option, $default=null)
128+
protected function getOption($option, $default=null)
113129
{
114130
if (isset($this->options[$option])) {
115131
return $this->options[$option];

Diff for: test/Nekland/Tests/Api/TestCase.php

+4-6
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414

1515
use Nekland\YoutubeApi\Youtube;
16+
use Prophecy\Argument;
1617

1718
class TestCase extends \PHPUnit_Framework_TestCase
1819
{
@@ -22,15 +23,12 @@ class TestCase extends \PHPUnit_Framework_TestCase
2223
*/
2324
protected function getYoutubeMock(array $data)
2425
{
25-
$httpClient = $this->getMock('Nekland\BaseApi\Http\ClientInterface');
26+
$httpClient = $this->prophesize('Nekland\BaseApi\Http\ClientInterface');
2627

2728
foreach($data as $method => $return) {
28-
$httpClient->expects($this->any())
29-
->method($method)
30-
->willReturn($return)
31-
;
29+
$httpClient->$method(Argument::cetera())->willReturn($return);
3230
}
3331

34-
return new Youtube($httpClient);
32+
return new Youtube($httpClient->reveal());
3533
}
3634
}

Diff for: test/Nekland/Tests/Http/Auth/AuthServiceTrait.php

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
/**
3+
* This file is a part of YoutubeApi package.
4+
*
5+
* (c) Nekland <[email protected]>
6+
*
7+
* For the full license, take a look to the LICENSE file
8+
* on the root directory of this project
9+
*/
10+
11+
namespace Nekland\Tests\Http\Auth;
12+
13+
14+
use Guzzle\Http\ClientInterface;
15+
use Guzzle\Http\Message\EntityEnclosingRequestInterface;
16+
use Guzzle\Http\Message\Response;
17+
use Prophecy\Argument;
18+
19+
trait AuthServiceTrait
20+
{
21+
protected function getClientMock()
22+
{
23+
$client = $this->prophesize(ClientInterface::class);
24+
$request = $this->prophesize(EntityEnclosingRequestInterface::class);
25+
$response = $this->prophesize(Response::class);
26+
27+
$response->getBody(Argument::cetera())->willReturn($this->getGoogleResponse());
28+
$request->send(Argument::any())->shouldBeCalled()->willReturn($response->reveal());
29+
$client->post(Argument::cetera())->willReturn($request->reveal());
30+
31+
return $client->reveal();
32+
}
33+
34+
protected function getGoogleResponse()
35+
{
36+
return '{
37+
"access_token" : "ya29.1.AADHN_WnGjqYiAcnONRLFDOfXia5XZLFO4RSyEhWtQPAvYpgPYiQj89c7UsrAs5_",
38+
"token_type" : "Bearer",
39+
"expires_in" : 3600
40+
}';
41+
}
42+
}
+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<?php
2+
/**
3+
* This file is a part of YoutubeApi package.
4+
*
5+
* (c) Nekland <[email protected]>
6+
*
7+
* For the full license, take a look to the LICENSE file
8+
* on the root directory of this project
9+
*/
10+
11+
namespace Nekland\Tests\Http\Auth;
12+
13+
14+
use Guzzle\Http\ClientInterface;
15+
use Guzzle\Http\Message\Request;
16+
use Nekland\YoutubeApi\Http\Auth\JsonFileServiceAuth;
17+
18+
class JsonFileServiceAuthTest extends \PHPUnit_Framework_TestCase
19+
{
20+
use AuthServiceTrait;
21+
22+
public function testItConstructWithOrWithoutClient()
23+
{
24+
$auth = new JsonFileServiceAuth();
25+
$this->assertInstanceOf(JsonFileServiceAuth::class, $auth);
26+
27+
$auth = new JsonFileServiceAuth($this->prophesize(ClientInterface::class)->reveal());
28+
$this->assertInstanceOf(JsonFileServiceAuth::class, $auth);
29+
}
30+
31+
public function testItAddsATokenToTheRequest()
32+
{
33+
$auth = new JsonFileServiceAuth($this->getClientMock());
34+
35+
// This file is a fake, of course.
36+
$file = __DIR__ . '/../../../../test_data/given_by_google.json';
37+
38+
$auth->setOptions(['json_file' => $file]);
39+
$request = new Request('POST', 'http://fake.com');
40+
$auth->auth($request);
41+
42+
$this->assertContains('ya29.1.AADHN_WnGjqYiAcnONRLFDOfXia5XZLFO4RSyEhWtQPAvYpgPYiQj89c7UsrAs5_',(string)$request->getHeader('Authorization'));
43+
}
44+
45+
/**
46+
* @expectedException \Nekland\YoutubeApi\Exception\MissingOptionException
47+
*/
48+
public function testItThrowsExceptionIfOptionMissing()
49+
{
50+
$auth = new JsonFileServiceAuth($this->prophesize(ClientInterface::class)->reveal());
51+
$request = new Request('POST', 'http://fake.com');
52+
$auth->auth($request);
53+
}
54+
}

0 commit comments

Comments
 (0)