This tool loads Firebase service-account private keys and uses them to mint signed tokens. That makes it roughly as sensitive as the key file itself. This document describes exactly what it does with your credentials so you can decide where it is appropriate to run.
Please report security issues privately through GitHub's private vulnerability reporting rather than opening a public issue. I'll acknowledge the report and, once a fix ships, credit you in the release notes unless you'd rather stay anonymous.
Settings are persisted by eframe to a single app.ron file:
| Platform | Location |
|---|---|
| Linux | ~/.local/share/firebase-token-toolkit/app.ron |
| macOS | ~/Library/Application Support/firebase-token-toolkit/app.ron |
| Windows | %APPDATA%\firebase-token-toolkit\data\app.ron |
Persisted for every profile:
- Service-account path — the filesystem path only. The key file's contents are read on demand and never copied into the config.
- Project ID, and the last-used tab.
- Window size and position.
- Each app's name, type, App ID, Android package name and SHA-1, and iOS bundle ID. These are public identifiers that ship inside every build of the app.
Persisted only when "remember API keys & debug tokens" is enabled:
- Each app's API key and App Check debug token.
These are stored in plaintext. There is no OS keychain integration — the file is
protected by nothing but its filesystem permissions. If you would not paste the value
into a plaintext file, leave "remember API keys & debug tokens" off. Turning it off clears those fields
for all profiles on the next save (clear_secrets_all in src/config.rs).
Never persisted: the service-account private key, OAuth access tokens, and any custom/ID token shown in the UI.
- The service-account private key, held for the lifetime of the loaded profile and
used to sign RS256 assertions (
src/firebase/jwt.rs). - OAuth access tokens, cached and refreshed automatically within 60 seconds of
expiry (
src/firebase/oauth.rs). Never written to disk.
Switching profiles drops the loaded service account, the cached OAuth token, the user list, and every tab's output.
All requests go to Google endpoints over TLS (rustls — no OpenSSL):
oauth2.googleapis.com/token— exchanges a signed JWT assertion for an access tokenidentitytoolkit.googleapis.com—signInWithCustomToken,accounts:batchGet,accounts:lookup,accounts:updatefirebaseappcheck.googleapis.com—exchangeDebugTokenfirebase.googleapis.com—searchAppsand each app's config and SHA certificates, when you click Load apps. The responses include the apps' API keys, which are held like any other API key above.
Requests made with an Android or iOS app's API key carry that app's package
name and SHA-1, or bundle ID, in the X-Android-Package, X-Android-Cert and
X-Ios-Bundle-Identifier headers, as the Firebase SDKs do.
There is no telemetry, analytics, or update check. The application makes no network request you did not initiate.
The only other thing that leaves the app is a link you click in the About dialog (Source, Contributors, Report an issue, Changelog, Security notes), which hands that URL to your system browser. Nothing is sent with it.
- The OAuth scopes are broad. Access tokens are requested with
auth/identitytoolkitandauth/cloud-platform(src/firebase/oauth.rs). The latter is a wide scope; the token is short-lived and memory-resident, but a service account with broad IAM roles will produce a correspondingly powerful token. - Tokens on screen are real credentials. A minted ID token authenticates as that user until it expires. Treat the window like a terminal showing secrets, and be careful about screen sharing.
- The UID picker displays real user PII — emails, phone numbers, and display names
are fetched via
accounts:batchGet. Keep that in mind before screenshotting. - Custom claims are written to the user record, not just to a token. Saving claims
calls
accounts:updateand affects every future ID token that user receives. - RS256 signing uses the RustCrypto backend.
jsonwebtokenis built with itsrust_cryptofeature, which brings in thersacrate. That crate carries an unresolved timing-sidechannel advisory for RSA private-key operations (RUSTSEC-2023-0071). Exploiting it requires precisely timing many signing operations, which is a concern for a network-exposed signing service rather than a desktop tool you run locally — but if you are signing with a key that matters, it is worth knowing. The alternative backend,aws_lc_rs, is constant-time but needs cmake and nasm, which breaks the cross-compiled Windows build. - The Windows build links the C runtime statically. That is what lets the executable start on a machine without the Visual C++ Redistributable, but it means Microsoft's runtime security fixes reach you only when this project rebuilds and publishes a new release, rather than through Windows Update.
- Prefer a non-production service account. Nothing here requires production credentials, and a development project limits the blast radius of a mistake.
This is a pre-1.0 project. Security fixes land on the latest release only.