kreait / firebase-php

Unofficial Firebase Admin SDK for PHP
https://firebase-php.readthedocs.io/
MIT License
2.19k stars 421 forks source link

Create tenant programmatically #837

Open fideloper opened 8 months ago

fideloper commented 8 months ago

Describe the feature you would like to see

Hi!

I'm looking into gcloud / firebase for multi-tenancy on a b2b saas.

It looks like the admin sdk can create tenants, but I can't find that in this PHP sdk - is it possible and I'm just missing it?

(NodeJS examle): https://cloud.google.com/identity-platform/docs/multi-tenancy-managing-tenants#node.js

admin.auth().tenantManager().createTenant({displayName: 'myTenant1',...})
    .then(...)
    .catch(...)

Perhaps that has to be done via google cloud API?

Thanks!

jeromegamez commented 8 months ago

That's currently not possible with the SDK, and I remember a PR from a few years ago that I wasn't ready to take on because Google IdP wasn't a core part of Firebase back then.

But if the official Admin SDKs have it (by now), I'll look into it.

In the meantime, it might be possible to use the Factory::createApiClient() to get an authenticated client and access the IdP REST APIs 🤞🏻

jeromegamez commented 8 months ago

Note to self: https://github.com/firebase/firebase-admin-node/blob/master/src/auth/tenant.ts

It seems to be part of the SDK since 2019, so I must have had another reason 😅

fideloper commented 8 months ago

Ha, gotcha!

It might hit the GCIP api instead of firebases API? I could imagine that being weird.

In any case, for future readers, here's how I got API calls working to Google Cloud's REST api without using an SDK (since it doesn't exist for this particular use case in PHP land):

(This is all within google cloud, not firebase):

  1. Create a Service Account with permission to the identitytoolkit api
  2. Generate/download a key for that service account (JSON file - it includes a private key and other data in it)

The code below shows:

  1. Generating a JWT
  2. Exchanging the JWT for an auth token to use in API calls
  3. Making an API call

This is in Laravel (with some adjustments to not be specific to a console command I made in Laravel to test) - it uses Laravel's HTTP facade to make requests:

use Carbon\Carbon;
use Firebase\JWT\JWT;

$jwt = JWT::encode(
    payload: [
        'iat' => Carbon::now()->timestamp,
        'exp' => Carbon::now()->addHour()->timestamp,
        'iss' => "your-service-accont@project-name.iam.gserviceaccount.com",
        'sub' => "your-service-accont@project-name.iam.gserviceaccount.com",
        'aud' => "https://www.googleapis.com/oauth2/v4/token",
        'scope' => "https://www.googleapis.com/auth/identitytoolkit",
    ],
    key: "<private key string extracted from service account JSON key file here>",
    alt: 'RS256'
);

// Exchange JWT for auth token
$exchange = HTTP::post("https://www.googleapis.com/oauth2/v4/token", [
    'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer',
    'assertion' => $jwt,
]);

if (! $exchange->successful()) {
    echo 'could not exchange jwt for token';
    return false;
}

// Make API calls as documented here:
// https://cloud.google.com/identity-platform/docs/reference/rest/v2/projects.tenants
$result = Http::withToken($exchange->json('access_token'))
    ->asJson()
    ->acceptJson()
    ->get("https://identitytoolkit.googleapis.com/v2/projects/<your-project>/tenants");

var_dump($result->status(), $result->json());
jeromegamez commented 8 months ago

Thanks for sharing, it will certainly help others with the same requirement! 🙏🏻

I'll keep the issue open as an enhancement so that you'll get notified if/when this lands in the SDK!