4

I'm trying to access Firebase from a server using PHP, the Google Auth library, and a wrapper for Firebase's REST...This works great to accomplish that:

use Firebase\JWT\JWT;
use Google\Auth\Credentials\ServiceAccountCredentials;
use Google\Auth\HttpHandler\HttpHandlerFactory;
use GuzzleHttp\Client;

$email = 'account@email.com';
$key = 'private_key_goes_here';

$scopes = [
    'https://www.googleapis.com/auth/userinfo.email',
    'https://www.googleapis.com/auth/firebase.database',
];

$creds = [
    'client_email' => $email,
    'private_key' => $key,
];

$serviceAccount = new ServiceAccountCredentials($scopes, $creds);
$handler = HttpHandlerFactory::build(new Client());
$token = $serviceAccount->fetchAuthToken($handler);

$firebase = new \Firebase\FirebaseLib($url, $token);
$value = $firebase->get('test/hello');
# $value now stores "world"

However, this requires the security rules in Firebase to be universal read / write, which I do not want. If I update my security rules to this:

{
  "rules": {
    "test": {
      ".read": "auth != null"
    }
  }
}

The result in $value becomes {"error": "Permission denied"}. I've searched extensively, and tried numerous permutations and possible solutions, with no conclusive results.

I've used this code to provide JWT tokens to end clients, which can successfully use them and leverage the security rules with no problem. I initially tried that same approach for the server, but was unsuccessful. I opted to try to combine the two methods:

# Snipping code that didn't change...
$serviceAccount = new ServiceAccountCredentials($scopes, $creds);
$handler = HttpHandlerFactory::build(new Client());

$payload = [
    'iss' => $email,
    'sub' => $email,
    'aud' => 'https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit',
    'iat' => time(),
    'exp' => time() + 60 * 60,
    'uid' => '123',
    'claims' => [
        'uid' => '123',
    ],
];

$payload = $serviceAccount->updateMetadata($payload);
$token = JWT::encode($payload, $key, 'RS256');

$firebase = new \Firebase\FirebaseLib($url, $token);
$value = $firebase->get('test/hello');

This seems to get close, but $value now contains {"error": "Missing claim 'kid' in auth header."}. To resolve this, I modified the encode call:

$token = JWT::encode($payload, $key, 'RS256', 'key_id_goes_here');

Which results in a slightly different error: Invalid claim 'kid' in auth header., suggesting I'm on the right track...But not quite there. Using the JWT token directly yields the exact same results. Any ideas what I'm doing wrong? The email, private key, and key id all came directly from the json credential file provided when I created the service account.

I've looked at dozens of pages of documentation and posts, here are the ones that were the most helpful:

Cross posted to the Firebase Google Group.

Community
  • 1
  • 1
dbburgess
  • 751
  • 6
  • 18

2 Answers2

2

You can specify an auth_variable_override query parameter when authenticating with a service account that will become the auth variable in the security rules. It should be a properly escaped JSON object. For example to do {"uid":123} you'd want to add:

?auth_variable_override=%7B%22uid%22%3A%22123%22%7D

to the end of your request URL.

Michael Bleigh
  • 25,334
  • 2
  • 79
  • 85
  • Thank you for the response. The PHP library has an options parameter which it uses to build a query string. I tried this (and many other permutations): `$value = $firebase->get('test/hello', ['auth_variable_override' => ['uid' => 123]]);` ...But to no avail, I'm still receiving a permission denied. I confirmed the url the lib is using is `https://sample-db.firebaseio.com/test.json?auth_variable_override=%7B%22uid%22%3A%22123%22%7D&auth%5Baccess_token%5D=token_here&auth%5Btoken_type%5D=Bearer&auth%5Bexpires_in%5D=3600` ....What am I missing? – dbburgess Jul 12 '16 at 22:00
1

Ultimately, the solution I ended up using was to switch PHP libraries. I initially dismissed this library because it is moving toward PHP7 only support, which I'm not ready to migrate to yet, but the current version (1.1) worked fine:

use Kreait\Firebase\Configuration;
use Kreait\Firebase\Firebase;

$clientId = '1234567890';
$email = 'account@email.com';
$key = 'private_key_goes_here';
$url = 'https://example.firebaseio.com';

$fbConfig = new Configuration();
$fbConfig->setAuthConfigFile([
    'type' => 'service_account',
    'client_id' => $clientId,
    'client_email' => $email,
    'private_key' => $key,
]);

$fb = new Firebase($url, $fbConfig);
$value = $fb->get('test/hello');
# $value now stores "world"
dbburgess
  • 751
  • 6
  • 18
  • Hi, Can you please give source code of your demo ? i also need to use firebase using php. please give source code of demo Thanks – s4suryapal Apr 16 '18 at 13:28