Skip to content

feat(cli): init fcm with Google sign-in for the Appwrite Push FCM provider - #1956

Open
ArnabChatterjee20k wants to merge 21 commits into
mainfrom
messaging-provider-cli
Open

ArnabChatterjee20k wants to merge 21 commits into
mainfrom
messaging-provider-cli

Conversation

@ArnabChatterjee20k

@ArnabChatterjee20k ArnabChatterjee20k commented Oct 1, 2026 •

Copy link
Copy Markdown
Member

What

appwrite init fcm sets up the FCM messaging provider that Appwrite Push uses to wake Android apps in the background. Developers no longer copy a service account key into the console by hand.

The command can create the key itself: the developer signs in with Google through the Appwrite console, and the CLI makes a dedicated service account in their Firebase project and uploads its key.

init apns and init push are in the stacked PR #1963, so this one can be released first.

Run it from the app's root, in a directory linked with appwrite init project.

Flags

Flag Meaning When omitted
--key-path <file> Firebase service account key (.json) A service account in the project folder. Otherwise asks: sign in with Google and create it, get one from the Firebase console, or use an existing file.
--project-id <id> Firebase project ID The app's google-services.json, lib/firebase_options.dart or .firebaserc. Otherwise a picker (from Google sign-in or the firebase CLI), or the key's project_id.
--application-id <id> Android application ID applicationId in Gradle, or Expo android.package. With several apps, a picker.

Global flags that matter here:

Flag Effect
--force / -f Replace the key on a provider that's already set up. Without it, a rerun reports "already set up" and changes nothing.
--config-file <path> Use another appwrite.config.json. Its folder is also searched for keys.

Usage

Interactive, with Google sign-in

appwrite init fcm
ℹ Info: Setting up FCM ...
? How would you like to provide the Firebase service account key (.json)?
  > Sign in with Google and create it automatically
    Get one from the Firebase console
    Use a file I already have
ℹ Info: Opening Google sign-in. Allow access to Google Cloud so Appwrite can create the key.
ℹ Info: The browser must be signed in to the Appwrite console as dev@example.com.
ℹ Info: Signed in to Google as dev@example.com.
? Which Firebase project should send push notifications?
  > Sticker Smash (sticker-smash-fb)
    Tools (tools-4821)
ℹ Info: Creating a service account that can send messages in sticker-smash-fb ...
✓ Success: Created service account appwrite-fcm-x1y2z3w4@sticker-smash-fb.iam.gserviceaccount.com and a key for it.
✓ Success: Created provider FCM (sticker-smash-fb) ( ... )
✓ Success: FCM is set up for Firebase project sticker-smash-fb.

Key already in the project folder

appwrite init fcm
# ℹ Info: Using sticker-smash-fb-firebase-adminsdk-x1.json from the project folder.

CI

appwrite init fcm --key-path service-account.json

Rotating the key

appwrite init fcm --force

How it works

Creating the key with Google

This works the same way as the console's one-click FCM setup (appwrite/vibes#514), using the console's existing Google sign-in. There's no separate OAuth app for the CLI.

  1. Token: if the CLI's Appwrite account already has a Google identity with a live access token, it's reused. Otherwise the CLI opens {endpoint}/account/tokens/oauth2/google?project=console&scopes[]=https://www.googleapis.com/auth/cloud-platform.

    • The browser lands back on the console.
    • The CLI polls GET /account/identities with its own session until a new Google token appears, for up to 5 minutes.
    • It needs no local callback server.
  2. Project: the CLI lists the user's Firebase projects (firebase.googleapis.com/v1beta1/projects) and always asks which one gets the key, even when there's only one. A project ID detected from the app's config, or passed as --project-id, must be in the list and is used directly.

  3. Already set up? If the chosen project already has an enabled FCM provider and --force isn't passed, the CLI stops before creating anything.

  4. APIs: serviceusage services:batchEnable turns on the FCM, IAM and Cloud Resource Manager APIs in the chosen project, and the CLI polls the operation until it's done.

    • This runs before the permission check, because that check calls the Cloud Resource Manager API itself.
    • It's best effort: if enabling fails (for example, not allowed), the CLI warns and continues in case the APIs are already on.
  5. Permissions: testIamPermissions checks for iam.serviceAccounts.create, iam.serviceAccountKeys.create and resourcemanager.projects.setIamPolicy.

  6. Key:

    • create an appwrite-fcm-xxxxxxxx service account;
    • grant it roles/firebasecloudmessaging.admin through a version 3 IAM policy, retrying while the new account propagates;
    • create a JSON key.

    Every call bills the user's project (X-Goog-User-Project), including revoking the key.

  7. Upload: the key is validated and uploaded straight into the provider, and never written to disk. If creating or updating the provider fails, the key is revoked.

Each blocker prints the reason and falls back to the browser or file options:

  • Google sign-in never reaches the CLI's Appwrite account, with a hint naming the console email the browser must be signed in as;
  • the Google Cloud permission wasn't granted;
  • missing IAM permissions;
  • an organization policy blocking key creation;
  • a disabled Google API, with its activation link. When listing projects fails this way, the message says the Firebase Management API must be enabled in the Appwrite server's own Google Cloud project, which is an administrator task.

Where the key comes from otherwise

  1. --key-path.
  2. The project folder: the folder holding appwrite.config.json, plus the folder the command runs in.
    • A valid service account is used without asking.
    • When there are several, the CLI asks which one.
    • One for another Firebase project is skipped with a warning.
  3. Prompt:
    • Get one from the Firebase console: the CLI opens the Service accounts page (project/_/ when the project is unknown) and waits up to 15 minutes for the file in the project folder or ~/Downloads.
    • Or an existing file.

A key file inside a git repository that isn't git-ignored gets a warning to add it to .gitignore.

What it detects

  • Modules applying com.android.application, and their application ID.
  • Every google-services.json (module root and flavour folders), Expo android.package / googleServicesFile, Flutter lib/firebase_options.dart, .firebaserc.
  • The Google services Gradle plugin and the firebase-messaging dependency, with hints when they're missing.
  • Only Firebase configs listing the chosen application ID count. A mismatch stops with an explanation.

Checks before anything is sent

  • The key must be a service_account with an RSA private key, and belong to the app's Firebase project.
  • A key found in the project folder doesn't replace an enabled provider without --force.
  • Without a terminal, a missing answer names the flag to pass.

Testing

  • Unit tests (initpush_test.go):
    • Detection: Gradle with flavours, Expo.
    • Key lookup: project folder, browser, the git ignore warning.
    • Firebase project selection.
    • Provider create-then-update against a fake messaging API.
    • Google flow against fake Google and Appwrite servers:
      • a reused linked token, and sign-in through the console;
      • the project picker;
      • missing permissions, and an org policy falling back to the browser;
      • key revocation when the provider is rejected;
      • "already set up" creating nothing.
  • Manual run against a local Appwrite with generated keys: the project-folder and browser flows, reruns, and each wrong-key and wrong-app case.
  • Not tested live: Google sign-in against real Google. It needs a console with Google OAuth (cloud-platform scope) and a Google account that owns a Firebase project.

Prerequisites for Google sign-in

The console's Google OAuth2 provider must allow the cloud-platform scope, and the Firebase Management API must be enabled in the OAuth client's Google Cloud project. This is the same setup appwrite/vibes#514 needs. On a self-hosted server without it, the CLI falls back to the other options.

Not in this PR

@hansi-codes

hansi-codes Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

🟢 Tier S · Ready to merge

The incremental changes preserve the setup and cleanup contracts, and no concrete defects were found.

Adds appwrite init fcm to detect Android/Firebase configuration, obtain validated service account credentials, and configure an Appwrite FCM provider. Credentials can come from local files, browser downloads, or Google sign-in that provisions a dedicated service account and key, with revocation when provider setup fails. The latest changes improve API enablement, IAM policy handling, quota attribution for revocation, and disabled-API guidance, with corresponding test coverage.

Latest changes: The newest commits enable Google APIs before checking permissions, surface enablement operation failures while allowing best-effort continuation, set IAM policy version 3, attribute key revocation to the selected project, and add clearer disabled-API guidance and regression tests.

Verdict New comments Fixed Still open
✅ Approved 0 0 0
📂 Walkthrough · 6
File Change
src/SDK/Language/CLI.php Registers the FCM setup, detection, Google provisioning, and test templates.
templates/cli/internal/cmd/init.go Registers the FCM initialization subcommand.
templates/cli/internal/cmd/initpush.go Implements credential acquisition, validation, provider setup, and cleanup of unused Google-created keys.
templates/cli/internal/cmd/initpushdetect.go Detects Android, Expo, and Firebase configuration and relevant dependencies.
templates/cli/internal/cmd/initpushgoogle.go Implements Google authentication, project selection, API enablement, IAM provisioning, and project-attributed key revocation.
templates/cli/internal/cmd/initpush_test.go Tests configuration detection, credential acquisition, provider setup, Google provisioning, API enablement, and failure cleanup.

Reviewed the commits since 934df79 · Details · Comment @hansi-codes review to re-run, or mention @hansi-codes with a question.

@hansi-codes hansi-codes Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Tier B · 1 blocking finding to address. Summary

Comment thread templates/cli/internal/cmd/initpush.go Outdated
Comment thread templates/cli/internal/cmd/initpushdetect.go Outdated
Comment thread templates/cli/internal/cmd/initpushdetect.go Outdated
Comment thread templates/cli/internal/cmd/initpush.go Outdated

@hansi-codes hansi-codes Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Tier S · Looks good to merge. Summary

@hansi-codes hansi-codes Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Tier B · 1 blocking finding to address. Summary

Comment thread templates/cli/internal/cmd/initpush.go

@hansi-codes hansi-codes Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Tier S · Looks good to merge. Summary

@ArnabChatterjee20k ArnabChatterjee20k changed the title feat(cli): init apns, init fcm and init push for Appwrite Push providers feat(cli): init fcm with Google sign-in for the Appwrite Push FCM provider Oct 5, 2026

@hansi-codes hansi-codes Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Tier A · Looks good to merge. Summary

Comment thread templates/cli/internal/cmd/initpush.go

@hansi-codes hansi-codes Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Tier S · Looks good to merge. Summary

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant