title: Firebase REST access using PHP with Authentication
body: <p>I'm trying to access Firebase from a server using PHP, the <a href="https://github.com/google/google-auth-library-php" rel="nofollow noreferrer">Google Auth library</a>, and a <a href="https://github.com/ktamas77/firebase-php" rel="nofollow noreferrer">wrapper</a> for Firebase's REST...This works great to accomplish that:</p>
  
  <pre><code>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' =&gt; $email,
      'private_key' =&gt; $key,
  ];
  
  $serviceAccount = new ServiceAccountCredentials($scopes, $creds);
  $handler = HttpHandlerFactory::build(new Client());
  $token = $serviceAccount-&gt;fetchAuthToken($handler);
  
  $firebase = new \Firebase\FirebaseLib($url, $token);
  $value = $firebase-&gt;get('test/hello');
  # $value now stores "world"
  </code></pre>
  
  <p>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:</p>
  
  <pre><code>{
    "rules": {
      "test": {
        ".read": "auth != null"
      }
    }
  }
  </code></pre>
  
  <p>The result in <code>$value</code> becomes <code>{"error": "Permission denied"}</code>. I've searched extensively, and tried numerous permutations and possible solutions, with no conclusive results.</p>
  
  <p>I've used <a href="https://stackoverflow.com/a/38002484/5191100">this code</a> 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:</p>
  
  <pre><code># Snipping code that didn't change...
  $serviceAccount = new ServiceAccountCredentials($scopes, $creds);
  $handler = HttpHandlerFactory::build(new Client());
  
  $payload = [
      'iss' =&gt; $email,
      'sub' =&gt; $email,
      'aud' =&gt; 'https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit',
      'iat' =&gt; time(),
      'exp' =&gt; time() + 60 * 60,
      'uid' =&gt; '123',
      'claims' =&gt; [
          'uid' =&gt; '123',
      ],
  ];
  
  $payload = $serviceAccount-&gt;updateMetadata($payload);
  $token = JWT::encode($payload, $key, 'RS256');
  
  $firebase = new \Firebase\FirebaseLib($url, $token);
  $value = $firebase-&gt;get('test/hello');
  </code></pre>
  
  <p>This seems to get close, but <code>$value</code> now contains <code>{"error": "Missing claim 'kid' in auth header."}</code>. To resolve this, I modified the encode call:</p>
  
  <pre><code>$token = JWT::encode($payload, $key, 'RS256', 'key_id_goes_here');
  </code></pre>
  
  <p>Which results in a slightly different error: <code>Invalid claim 'kid' in auth header.</code>, 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 <code>json</code> credential file provided when I created the service account.</p>
  
  <p>I've looked at dozens of pages of documentation and posts, here are the ones that were the most helpful:</p>
  
  <ul>
  <li><a href="https://firebase.google.com/docs/auth/server#use_a_jwt_library" rel="nofollow noreferrer">Using JWT for Server Auth (Firebase Docs)</a></li>
  <li><a href="https://stackoverflow.com/a/37444914/5191100">Using Custom Tokens to make REST requests to FB DB as an admin</a></li>
  <li><a href="https://stackoverflow.com/a/37492640/5191100">Is it still possible to do server side verification of tokens in Firebase 3?</a></li>
  </ul>
  
  <p><em>Cross posted to the <a href="https://groups.google.com/d/topic/firebase-talk/OiS9op9_c94/discussion" rel="nofollow noreferrer">Firebase Google Group</a>.</em></p>