Skip to content

Commit 25f3214

Browse files
authored
Support configuration of credentials with a config array (#202)
1 parent 10cc86b commit 25f3214

File tree

5 files changed

+97
-24
lines changed

5 files changed

+97
-24
lines changed

README.md

+34-7
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ Please read about the future of the Firebase Admin PHP SDK on the
2121
- [Installation](#installation)
2222
- [Laravel](#laravel)
2323
- [Configuration](#configuration)
24+
- [Credentials with JSON files](#credentials-with-json-files)
25+
- [Credentials with Arrays](#credentials-with-arrays)
2426
- [Usage](#usage)
2527
- [Multiple projects](#multiple-projects)
2628
- [Supported Versions](#supported-versions)
@@ -37,12 +39,6 @@ composer require kreait/laravel-firebase
3739
In order to access a Firebase project and its related services using a server SDK, requests must be authenticated.
3840
For server-to-server communication this is done with a Service Account.
3941

40-
The package uses auto discovery for the default project to find the credentials needed for authenticating requests to
41-
the Firebase APIs by inspecting certain environment variables and looking into Google's well known path(s).
42-
43-
If you don't want a service account to be auto-discovered, provide it by setting the `GOOGLE_APPLICATION_CREDENTIALS`
44-
environment variable or by adapting the package configuration.
45-
4642
If you don't already have generated a Service Account, you can do so by following the instructions from the
4743
official documentation pages at https://firebase.google.com/docs/admin/setup#initialize_the_sdk.
4844

@@ -64,6 +60,37 @@ by copying it to your local `config` directory or by defining the environment va
6460
php artisan vendor:publish --provider="Kreait\Laravel\Firebase\ServiceProvider" --tag=config
6561
```
6662

63+
### Credentials with JSON files
64+
65+
The package uses auto discovery for the default project to find the credentials needed for authenticating requests to
66+
the Firebase APIs by inspecting certain environment variables and looking into Google's well known path(s).
67+
68+
If you don't want a service account to be auto-discovered, provide it by setting the `FIREBASE_CREDENTIALS` or `GOOGLE_APPLICATION_CREDENTIALS` environment variable or by adapting the package configuration, like so for example:
69+
70+
```.env
71+
FIREBASE_CREDENTIALS=storage/app/firebase-auth.json
72+
```
73+
74+
### Credentials with Arrays
75+
76+
If you prefer to have more control over the configuration items required to configure the credentials, you can also transpose the Service Account JSON file as an array within your `config/firebase.php` file.
77+
78+
```php
79+
'credentials' => [
80+
'type' => 'service_account',
81+
'project_id' => 'some-project-123',
82+
'private_key_id' => '123456789',
83+
'private_key' => '-----BEGIN PRIVATE KEY-----\nFOO_BAR_123456789\n-----END PRIVATE KEY-----\n',
84+
'client_email' => '[email protected]',
85+
'client_id' => '123456789',
86+
'auth_uri' => 'https://accounts.google.com/o/oauth2/auth',
87+
'token_uri' => 'https://oauth2.googleapis.com/token',
88+
'auth_provider_x509_cert_url' => 'https://www.googleapis.com/oauth2/v1/certs',
89+
'client_x509_cert_url' => 'https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-cwiuo%40some-project-123.iam.gserviceaccount.com',
90+
'universe_domain' => 'googleapis.com',
91+
],
92+
```
93+
6794
## Usage
6895

6996
Once you have retrieved a component, please refer to the [documentation of the Firebase PHP Admin SDK](https://firebase-php.readthedocs.io)
@@ -96,7 +123,7 @@ Earlier versions will receive security fixes as long as their **lowest** SDK req
96123
can find the currently supported versions and support options in the [SDK's README](https://github.com/kreait/firebase-php).
97124

98125
| Version | Initial Release | Supported SDK Versions | Supported Laravel Versions | Status |
99-
|---------|-----------------|------------------------|----------------------------|-------------|
126+
| ------- | --------------- | ---------------------- | -------------------------- | ----------- |
100127
| `5.x` | 13 Jan 2023 | `^7.0` | `^9.0` | Active |
101128
| `4.x` | 09 Jan 2022 | `^6.0` | `^8.0` | End of life |
102129
| `3.x` | 01 Nov 2020 | `^5.24` | `^6.0, ^7.0, ^8.0` | End of life |

config/firebase.php

+2-6
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,7 @@
4646
* first time you try to access a component of the Firebase Admin SDK.
4747
*
4848
*/
49-
'credentials' => [
50-
'file' => env('FIREBASE_CREDENTIALS', env('GOOGLE_APPLICATION_CREDENTIALS')),
51-
],
49+
'credentials' => env('FIREBASE_CREDENTIALS', env('GOOGLE_APPLICATION_CREDENTIALS')),
5250

5351
/*
5452
* ------------------------------------------------------------------------
@@ -180,9 +178,7 @@
180178
*/
181179
'timeout' => env('FIREBASE_HTTP_CLIENT_TIMEOUT'),
182180

183-
'guzzle_middlewares' => [
184-
185-
]
181+
'guzzle_middlewares' => [],
186182
],
187183
],
188184
],

src/FirebaseProjectManager.php

+7-6
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ protected function configuration(string $name): array
4747
return $config;
4848
}
4949

50-
protected function resolveCredentials(string $credentials): string
50+
protected function resolveJsonCredentials(string $credentials): string
5151
{
5252
$isJsonString = \str_starts_with($credentials, '{');
5353
$isAbsoluteLinuxPath = \str_starts_with($credentials, '/');
@@ -68,10 +68,12 @@ protected function configure(string $name): FirebaseProject
6868
$factory = $factory->withTenantId($tenantId);
6969
}
7070

71-
if ($credentials = $config['credentials']['file'] ?? null) {
72-
$resolvedCredentials = $this->resolveCredentials((string) $credentials);
71+
if ($credentials = $config['credentials']['file'] ?? ($config['credentials'] ?? null)) {
72+
if (is_string($credentials)) {
73+
$credentials = $this->resolveJsonCredentials($credentials);
74+
}
7375

74-
$factory = $factory->withServiceAccount($resolvedCredentials);
76+
$factory = $factory->withServiceAccount($credentials);
7577
}
7678

7779
if ($databaseUrl = $config['database']['url'] ?? null) {
@@ -97,8 +99,7 @@ protected function configure(string $name): FirebaseProject
9799

98100
$factory = $factory
99101
->withVerifierCache($cache)
100-
->withAuthTokenCache($cache)
101-
;
102+
->withAuthTokenCache($cache);
102103
}
103104

104105
if ($logChannel = $config['logging']['http_log_channel'] ?? null) {

tests/FirebaseProjectManagerTest.php

+53-4
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ final class FirebaseProjectManagerTest extends TestCase
1919
{
2020
protected function defineEnvironment($app): void
2121
{
22-
$app['config']->set('firebase.projects.app.credentials.file', __DIR__ . '/_fixtures/service_account.json');
22+
$app['config']->set('firebase.projects.app.credentials', __DIR__ . '/_fixtures/service_account.json');
2323
}
2424

2525
/**
@@ -66,7 +66,28 @@ public function calls_are_passed_to_default_project(): void
6666
/**
6767
* @test
6868
*/
69-
public function credentials_can_be_configured(): void
69+
public function credentials_can_be_configured_using_a_json_file(): void
70+
{
71+
// Reference credentials
72+
$credentialsPath = \realpath(__DIR__ . '/_fixtures/service_account.json');
73+
$credentials = \json_decode(\file_get_contents($credentialsPath), true);
74+
75+
// Set configuration and retrieve project
76+
$projectName = 'app';
77+
$this->app->config->set('firebase.projects.' . $projectName . '.credentials', \realpath(__DIR__ . '/_fixtures/service_account.json'));
78+
$factory = $this->factoryForProject($projectName);
79+
80+
// Retrieve service account
81+
$serviceAccount = $this->getAccessibleProperty($factory, 'serviceAccount')->getValue($factory);
82+
83+
// Validate value
84+
$this->assertSame($credentials, $serviceAccount);
85+
}
86+
87+
/**
88+
* @test
89+
*/
90+
public function json_file_credentials_can_be_used_using_the_deprecated_configuration_entry(): void
7091
{
7192
// Reference credentials
7293
$credentialsPath = \realpath(__DIR__ . '/_fixtures/service_account.json');
@@ -84,6 +105,34 @@ public function credentials_can_be_configured(): void
84105
$this->assertSame($credentials, $serviceAccount);
85106
}
86107

108+
/**
109+
* @test
110+
*/
111+
public function credentials_can_be_configured_using_an_array(): void
112+
{
113+
// Set configuration and retrieve project
114+
$projectName = 'app';
115+
$this->app->config->set('firebase.projects.' . $projectName . '.credentials', $credentials = [
116+
'type' => 'service_account',
117+
'project_id' => 'project',
118+
'private_key_id' => 'private_key_id',
119+
'private_key' => '-----BEGIN PRIVATE KEY-----\nsome gibberish\n-----END PRIVATE KEY-----\n',
120+
'client_email' => '[email protected]',
121+
'client_id' => '1234567890',
122+
'auth_uri' => 'https://some.google.tld/o/oauth2/auth',
123+
'token_uri' => 'https://some.google.tld/o/oauth2/token',
124+
'auth_provider_x509_cert_url' => 'https://some.google.tld/oauth2/v1/certs',
125+
'client_x509_cert_url' => 'https://some.google.tld/robot/v1/metadata/x509/user%40project.iam.gserviceaccount.com',
126+
]);
127+
$factory = $this->factoryForProject($projectName);
128+
129+
// Retrieve service account
130+
$serviceAccount = $this->getAccessibleProperty($factory, 'serviceAccount')->getValue($factory);
131+
132+
// Validate value
133+
$this->assertSame($credentials, $serviceAccount);
134+
}
135+
87136
/**
88137
* @test
89138
*/
@@ -101,8 +150,8 @@ public function projects_can_have_different_credentials(): void
101150
$secondProjectName = 'another-app';
102151

103152
// Set service accounts explicitly
104-
$this->app->config->set('firebase.projects.' . $projectName . '.credentials.file', \realpath(__DIR__ . '/_fixtures/service_account.json'));
105-
$this->app->config->set('firebase.projects.' . $secondProjectName . '.credentials.file', \realpath(__DIR__ . '/_fixtures/another_service_account.json'));
153+
$this->app->config->set('firebase.projects.' . $projectName . '.credentials', \realpath(__DIR__ . '/_fixtures/service_account.json'));
154+
$this->app->config->set('firebase.projects.' . $secondProjectName . '.credentials', \realpath(__DIR__ . '/_fixtures/another_service_account.json'));
106155

107156
// Retrieve factories and service accounts
108157
$factory = $this->factoryForProject($projectName);

tests/ServiceProviderTest.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ final class ServiceProviderTest extends TestCase
1616
*/
1717
public function it_provides_components(): void
1818
{
19-
$this->app->config->set('firebase.projects.app.credentials.file', \realpath(__DIR__ . '/_fixtures/service_account.json'));
19+
$this->app->config->set('firebase.projects.app.credentials', \realpath(__DIR__ . '/_fixtures/service_account.json'));
2020

2121
$this->assertInstanceOf(Firebase\Contract\AppCheck::class, $this->app->make(Firebase\Contract\AppCheck::class));
2222
$this->assertInstanceOf(Firebase\Contract\Auth::class, $this->app->make(Firebase\Contract\Auth::class));

0 commit comments

Comments
 (0)