Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Firebase Token Toolkit

Firebase Token Toolkit is a desktop app for getting the Firebase auth tokens you need while developing and testing a backend. Pick a user, click Generate, and you have a real ID token for that user, with its claims decoded underneath and a Copy button next to it. Paste it into Postman, curl or your own tests to call any API that verifies Firebase ID tokens.

It covers five jobs, each on its own tab:

TabWhat it does
UID -> Custom TokenSigns a custom token for a user with your service-account key.
UID -> ID TokenSigns a custom token and immediately exchanges it, giving you an ID token in one click.
Custom -> ID TokenExchanges a custom token you already have for an ID token.
User Custom ClaimsReads and edits the custom claims stored on a user record.
App CheckExchanges an App Check debug token for an App Check token.

A Users panel on the left lists the project’s users and searches them by email, phone or UID, so you rarely need to look a UID up by hand. Profiles keep the settings for several Firebase projects side by side, and each profile can hold the project’s web, Android and iOS apps, including API keys that are restricted to one app.

The app is a single native binary for Linux, Windows and macOS. It talks only to Google’s endpoints, only when you click something, and never writes your private key or the tokens it mints to disk.

Where to start

  1. Install the app.
  2. Collect what you need from your Firebase project: usually just a service-account key. The app can read the project’s web, Android and iOS apps itself.
  3. Follow the Quick start to your first ID token.

Have a specific question? The FAQ answers the common ones.

Use a development project. A service-account key can sign in as any user in its project, and the app shows real tokens on screen. Read the Security page before pointing it at anything that matters.

If you find this useful, please consider starring the project on GitHub, it really helps!

Installation

Download the archive for your platform from the latest release. There is no installer and nothing else to install: the app is a single native binary with no Node, webview, or Java runtime behind it.

PlatformArchiveRequirements
Linuxfirebase-token-toolkit-<version>-x86_64-linux.tar.gzx86_64, glibc 2.35 or newer (Ubuntu 22.04 and later)
Windowsfirebase-token-toolkit-<version>-x86_64-windows.zipx86_64
macOSfirebase-token-toolkit-<version>-universal-macos.dmgmacOS 11 or newer, Apple Silicon or Intel

Each release also publishes SHA256SUMS. To check a download before running it on Linux or macOS:

sha256sum --check --ignore-missing SHA256SUMS   # macOS: shasum -a 256 -c --ignore-missing SHA256SUMS

Linux

tar xzf firebase-token-toolkit-*-x86_64-linux.tar.gz
cd firebase-token-toolkit-*-x86_64-linux
./firebase-token-toolkit

Two parts of the app lean on the desktop environment:

  • The Browse… button opens the file chooser through an XDG desktop portal. GNOME, KDE and most other desktops ship one. On a bare window manager, install xdg-desktop-portal-gtk or an equivalent, or the picker will not open.
  • The Copy buttons write to the X11 clipboard. Under Wayland that needs XWayland, which nearly every Wayland session runs by default. If a copy fails, the error appears next to the button instead of failing silently.

Windows

Unzip the archive and run firebase-token-toolkit.exe.

The binary is not code-signed, so SmartScreen may stop it on first launch. Choose More info, then Run anyway. The C runtime is linked statically, so you do not need the Visual C++ Redistributable.

macOS

Open the .dmg and drag Firebase Token Toolkit into Applications.

The app is ad-hoc signed but not notarized, because the project has no Apple Developer account. Gatekeeper therefore blocks the first launch. Either right-click the app, choose Open, then Open again in the dialog, or clear the quarantine flag from a terminal:

xattr -dr com.apple.quarantine "/Applications/Firebase Token Toolkit.app"

Updating

Download the new archive and replace the old binary. Your profiles and settings live outside the app (see Settings and storage), so they carry over.

Building from source

If there is no build for your platform, or you would rather compile it yourself, see Building and contributing.

Preparing your Firebase project

The app needs up to three things from your Firebase project: a service-account key, the project ID, and the details of the apps you test with. Which ones depend on the tabs you plan to use:

TabService-account keyProject IDApp’s API keyApp ID
UID -> Custom Token✔for the Users panel
UID -> ID Token✔for the Users panel✔
Custom -> ID Token✔
User Custom Claims✔✔
App Check✔✔✔

Use a development project. Nothing in the app needs production credentials, and a service-account key can sign in as any user in its project. See Security.

Service-account key

  1. Open the Firebase console and pick your project.
  2. Go to Project settings → Service accounts.
  3. Click Generate new private key, then Generate key. A JSON file downloads.

Keep the file somewhere stable. The app saves its path, not its contents, and reads it again on every launch.

The key the console generates belongs to the project’s firebase-adminsdk-…@<project>.iam.gserviceaccount.com account, which already has the access the app needs. If you use a different service account, it needs permission to read and update Firebase Authentication users for the Users panel and the User Custom Claims tab, for example the Firebase Authentication Admin role (roles/firebaseauth.admin). Signing custom tokens happens locally with the key and needs no extra role.

Project ID

The app fills this in from the service-account file, so you rarely need to type it. It is also shown under Project settings → General.

Apps: web, Android and iOS

Each profile holds a list of the project’s apps, and the tabs that need an API key use the one you select. Any app registered in the project works, whatever its platform.

The quick way: with the service-account key loaded, click Load apps in the top bar. The app reads every web, Android and iOS app in the project through the Firebase Management API and fills in each app’s App ID, API key, package name and SHA-1 (Android) or bundle ID (iOS). See The top bar.

The service account needs to be allowed to read Firebase apps (firebase.clients.list and firebase.clients.get). The key the console generates already is; for another account, the Firebase Viewer role (roles/firebase.viewer) covers it.

By hand: under Project settings → General → Your apps, each app shows its App ID, for example 1:316659987175:android:b9522e663c7b203d12a842. Its API key is in the config file offered there (google-services.json, GoogleService-Info.plist, or the web snippet’s apiKey). The project-wide Web API Key on the same page also works for any app, as long as it has no application restriction.

API keys restricted to an app

Google Cloud lets you restrict a key to particular Android apps (package name plus signing-certificate SHA-1) or iOS apps (bundle ID). Google accepts such a key only from a request that names the app, the way the Firebase SDKs do. The app sends those details for you, taken from the selected app:

App typeSent with the request
Webthe API key only
AndroidX-Android-Package (package name) and X-Android-Cert (SHA-1)
iOSX-Ios-Bundle-Identifier (bundle ID)

So for a restricted key, make sure the app’s Package and SHA-1, or Bundle ID, match one of the entries in the key’s restriction. Load apps fills them from Firebase, using the first SHA-1 certificate registered for an Android app; if the key allows a different certificate, paste that one in.

If you have restricted which APIs a key may call, allow at least the Identity Toolkit API, and the Firebase App Check API if you use the App Check tab.

App Check debug token (App Check only)

The App Check tab exchanges a debug token you have registered for the app. This works the same for web, Android and iOS apps:

  1. Register the app with App Check under App Check → Apps if you have not already.
  2. Open the app’s overflow menu (⋮) and choose Manage debug tokens.
  3. Click Add debug token, give it a name, and either generate a token or paste one your client printed (the browser console on the web, Logcat on Android, the Xcode console on iOS). Copy the value; it is a UUID.

Treat the debug token like a password. Anyone holding it can get valid App Check tokens for your app.

Quick start

This walk-through goes from a fresh install to an ID token for one of your users. You need a service-account key file; see Preparing your Firebase project if you do not have one yet. The app reads everything else from the project.

1. Open the app

On first launch the status indicator reads not configured in red, and the tabs ask you to load a service account.

2. Load the service-account key

Click Browse… next to Service account and choose the JSON key file.

The path appears in the top bar, Project ID fills itself in from the key, and the indicator changes to SA only. A green Service account loaded message confirms it; click dismiss to hide it.

3. Load the project’s apps

Click Load apps. The app lists the project’s web, Android and iOS apps and fills in each one’s App ID and API key. Pick the app you want to test as from the App dropdown; the indicator turns green and reads ready.

If the service account is not allowed to read apps, enter an app by hand instead: + Add app, choose its type, and paste its API key and App ID. See The top bar.

4. Load your users

Click Load users in the Users panel. The app fetches up to 5,000 users and lists each one by email (or phone number), display name and UID.

5. Generate an ID token

  1. Click a user in the list. Their UID appears under Selected UID in the top bar.
  2. Open the UID -> ID Token tab.
  3. Click Generate.

The ID token appears in a box with a Copy button. Under it are a shortened refresh token, the time until the token expires, and a collapsible Decoded JWT claims table.

Click Copy and use the token wherever your backend expects one, for example:

curl -H "Authorization: Bearer <paste token here>" https://localhost:8080/api/me

6. Keep the setup for next time

The service-account path, Project ID and app list are saved automatically. API keys are saved only if you tick remember API keys & debug tokens; without it, click Load apps again after each launch, or paste the key. See Settings and storage for what that writes to disk.

Next steps

The top bar

Everything the tabs need comes from the top bar. Its values belong to the active profile, so switching profiles swaps them all at once. The first rows hold the profile and service account; the last two hold the selected app.

Service account

Browse… opens a file chooser for the service-account JSON key. When the key loads, a green Service account loaded message appears, and if Project ID is empty it is filled in from the key.

Clear unloads the key and clears the selected user. It also clears Project ID, but only if the key filled that value in and you have not edited it since.

The app stores the file’s path, not its contents, and reads the key again on every launch. If the file has moved, the profile starts with no service account loaded.

Status indicator

The indicator to the right of the service account shows what the app can do right now:

IndicatorMeaningTabs available
not configured (red)No service account loadedCustom -> ID Token and App Check only, given an app with an API key
SA only (yellow)Service account loaded, the selected app has no API keyUID -> Custom Token, User Custom Claims, the Users panel
ready (green)Service account, and the selected app has an API keyAll tabs (App Check also needs the app’s App ID)

Project ID

The Firebase project ID, for example fir-token-toolkit-demo. The Users panel, User Custom Claims and App Check use it to build their requests. It normally comes from the key file, but you can edit it.

remember API keys & debug tokens

Off by default. When ticked, every app’s API key and App Check debug token are saved to disk in plaintext, for every profile. When unticked, they are kept in memory only and cleared from every profile the next time the app saves. App names, App IDs and the Android and iOS identifiers are always saved: they are not secret, and they ship inside every build of the app. See Settings and storage.

Apps

A profile holds a list of the project’s apps, and the tabs that call Google with an API key (UID -> ID Token, Custom -> ID Token and App Check) use the one selected in the App dropdown.

ControlWhat it does
App dropdownSelects the app, listed as name (type). Switching clears the output of the three API-key tabs, but not the user list or the other tabs.
nameRenames the selected app.
+ Add appAdds an empty Web, Android or iOS app and selects it.
RemoveRemoves the selected app. Removing the last one leaves an empty web app.
Load appsImports the project’s apps from Firebase. Needs the service account and Project ID.
TypeWeb, Android or iOS. Decides which identifying headers go with the API key.
API keyThe key sent with requests for this app. Masked.
App IDThe app’s Firebase App ID. Pasting one sets Type to match, and renames an app still carrying a default name such as Web app.
Package, SHA-1Android only: the package name and signing-certificate SHA-1.
Bundle IDiOS only.

Load apps matches apps on their App ID, so running it again updates the list rather than duplicating it. It refreshes each app’s type, package, bundle ID and API key from Firebase, but keeps a name or SHA-1 you changed yourself.

The Package and SHA-1, or Bundle ID, matter only for an API key restricted to an Android or iOS app; see API keys restricted to an app. A SHA-1 that is not 40 hex digits (colons are fine) is marked invalid in yellow and is not sent.

Selected UID

Once you pick a user in the Users panel, a Selected UID row shows their UID and, in grey, their email or phone and display name. The UID-based tabs act on this user.

Profiles

A profile holds one project’s settings: service-account path, Project ID, and the project’s apps with their API keys and App Check debug tokens. Keep one per Firebase project, for example Dev, Staging and Production, and switch between them from the Profile dropdown.

Managing profiles

ControlWhat it does
Profile dropdownSwitches to another profile. Unnamed profiles are listed as (unnamed #N).
nameRenames the active profile as you type.
+ NewCreates an empty profile called Profile N and switches to it.
DeleteRemoves the active profile straight away, without asking first.

If you delete the only profile, an empty Default profile replaces it. Delete is greyed out when there is nothing to delete: a single profile with no service account and no API key.

What switching does

Switching profiles gives you a clean slate. The app:

  • loads the new profile’s service account from its saved path,
  • clears the user list and the selected user,
  • discards the cached OAuth access token,
  • clears the output of every tab.

Nothing from one project leaks into another, so a token on screen always belongs to the profile shown in the dropdown.

Saving

Profile names, service-account paths, Project IDs and app lists are always saved. API keys and debug tokens are saved only while remember API keys & debug tokens is ticked, and that checkbox applies to every profile, not just the active one. See Settings and storage.

The Users panel

The panel on the left lists the project’s Firebase Authentication users so you can pick one instead of copying UIDs around. It appears on the tabs that act on a user: UID -> Custom Token, UID -> ID Token and User Custom Claims.

It needs a loaded service account and a Project ID. Without them it shows Load a service account and set Project ID to browse users.

Loading users

Click Load users. The app fetches users 1,000 at a time, up to 5,000 in total, and the button becomes Refresh. A counter shows how many users are loaded and how many match the search box.

Each row shows:

  • the user’s email, or their phone number if they have no email, or (no email/phone),
  • their display name after a dash, if they have one,
  • their UID on the second line.

Click a row to select that user. The row is highlighted and the user appears under Selected UID in the top bar.

Filtering and looking up

The search box does two different things.

Typing filters the loaded list. Matching is case-insensitive and covers email, phone, display name and UID, so example keeps every @example.com user and +1555 finds phone users. Nothing is sent to Google.

Pressing Enter or clicking Lookup asks Firebase directly. Use it for users outside the loaded 5,000, or without loading the list at all. The query must be a complete value, and its form decides what is searched:

Query starts with or containsLooked up asExample
starts with +Phone number+15555550123
contains @Email (case does not matter)alice@example.com
anything elseUIDGx9uWZg06RdT9wLNWM0w9VdRNqv1

A user found this way is selected and added to the top of the list. If nobody matches, the panel says so:

Privacy

The list shows real personal data from your project: emails, phone numbers and display names. Keep that in mind before sharing your screen or a screenshot.

UID -> Custom Token

Signs a Firebase custom token for the selected user with your service-account key. Signing happens on your machine; nothing is sent over the network.

Needs: a service account and a selected user.

Generating a token

  1. Pick a user in the Users panel.
  2. Optionally, enter claims in Custom claims (optional JSON).
  3. Click Generate.

The token appears under Custom Token with a Copy button. Open Decoded JWT claims to see what was signed.

A custom token is valid for one hour. It is not an ID token: a client signs in with it, using signInWithCustomToken in a Firebase SDK, and receives an ID token back. To skip that step, use UID -> ID Token.

Adding claims to one token

Claims typed here go into the token’s claims field and are carried into the ID token that the custom token is exchanged for. They are not stored on the user, so the next token you generate starts without them.

The box must hold a JSON object, such as:

{"tier": "beta", "beta_features": ["new-checkout"]}

To give a user claims that appear in every token they receive, use User Custom Claims instead.

What the token contains

ClaimValue
iss, subThe service account’s email address
audhttps://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit
uidThe selected user’s UID
iat, expIssue time, and expiry one hour later
claimsYour optional claims, if any

UID -> ID Token

Gets a Firebase ID token for the selected user in one click. The app signs a custom token locally, exchanges it with Google through signInWithCustomToken, and shows the resulting ID token.

Needs: a service account, an app with an API key, and a selected user. The exchange uses the selected app’s key, so you can check that an Android or iOS app’s restricted key works.

Generating a token

  1. Pick a user in the Users panel.
  2. Optionally, enter claims in Custom claims (optional JSON). They are added to this token only.
  3. Click Generate.

Under the token you get:

  • Refresh token: a shortened view of the refresh token Google returned. It is shown for reference only; there is no button to copy it.
  • Expires in: the token’s lifetime in seconds, normally 3600s.
  • Decoded JWT claims: everything the ID token asserts. Claims stored on the user with User Custom Claims appear here alongside the standard ones.

Using the token

Send it as a bearer token to anything that verifies Firebase ID tokens, such as your backend’s verifyIdToken call or a Firebase security rule test:

curl -H "Authorization: Bearer $ID_TOKEN" https://localhost:8080/api/me

The token is a real credential for that user until it expires. Treat it like a password.

Signing in as the user

Exchanging a custom token is a real sign-in. The user’s Signed in date in the Firebase console updates, auth_time in the token is set to now, and the firebase claim records "sign_in_provider": "custom". If your backend treats the sign-in provider specially, or you track sign-in activity, bear that in mind.

Custom -> ID Token

Exchanges a custom token you already have for an ID token, by calling accounts:signInWithCustomToken. Use it to check a custom token minted somewhere else, such as by your own backend, or one copied from the UID -> Custom Token tab.

Needs: an app with an API key. No service account is required, so this tab works in a profile that only has an app’s key.

Exchanging a token

  1. Paste the token into Custom token.
  2. Click Exchange.

The result shows the ID token with a Copy button, Expires in, and the decoded claims. Claims carried in the custom token, such as tier above, show up next to the ones stored on the user (plan and role).

Unlike UID -> ID Token, this tab does not show the refresh token.

When the exchange fails

Errors appear in red under the button, with Google’s message passed through. The common ones:

  • INVALID_CUSTOM_TOKEN : Invalid assertion format. 3 dot separated segments required. means the paste is incomplete.
  • INVALID_CUSTOM_TOKEN with other text usually means the token has expired. Custom tokens last one hour.
  • CREDENTIAL_MISMATCH means the token was signed by a different project from the one the API key belongs to.

See Troubleshooting for more.

User Custom Claims

Reads and edits the custom claims stored on a user’s record (customAttributes in the Identity Toolkit API). Unlike the claims box on the token tabs, these are permanent: Firebase adds them to every ID token the user gets from now on, until you change them.

Needs: a service account, a Project ID, and a selected user.

Viewing a user’s claims

Select a user and click Load current. The editor fills with their claims, and the message says either Loaded current custom claims. or Loaded — user has no custom claims set.

Pretty-print reformats the JSON with indentation and sorted keys. If the JSON is invalid, it reports Invalid JSON: and the parser’s message instead.

Selecting a different user clears the editor, so you cannot accidentally save one user’s claims onto another.

Changing claims

  1. Click Load current so you start from what is stored.
  2. Edit the JSON. It must be an object, for example {"role": "admin", "plan": "pro", "level": 3}.
  3. Click Save.

The editor replaces the user’s claims entirely; it does not merge. Any key you remove from the JSON is removed from the user.

The 1,000-byte limit

Firebase rejects claims larger than 1,000 bytes. A counter under the editor measures the claims compactly serialized, which is how Firebase counts them, so whitespace from Pretty-print does not count:

  • grey 39 / 1000 bytes serialized: within the limit,
  • red 1040 / 1000 bytes (Firebase will reject): too large; Save refuses with an error,
  • yellow (invalid JSON — fix before saving).

Keep claims small. They travel in every token and every request, and they suit roles and flags rather than profile data.

Removing all claims

Saving an empty editor is refused on purpose, to avoid wiping claims by accident. To remove everything, click Clear all claims. It saves an empty claims object ({}), and the message reads Saved — all custom claims cleared. Loading a user whose claims are {} shows an empty editor and Loaded — user has no custom claims set.

When changes take effect

Tokens already issued keep the old claims until they expire, about an hour. A client can pick up the change sooner by force-refreshing its token, for example getIdToken(true) in the Firebase JavaScript SDK. New tokens from UID -> ID Token include the change immediately.

App Check

Exchanges an App Check debug token for a real App Check token. Use it to call App Check–protected backends, such as Cloud Functions or your own server, from scripts or API tools that cannot run the App Check SDK.

Needs: the Project ID, and an app with an App ID and API key. No service account is required. It works for web, Android and iOS apps; the tab names the app it will use.

Before you start

Register a debug token for the app in the Firebase console under App Check → Apps → ⋮ → Manage debug tokens. The steps are in Preparing your Firebase project.

Exchanging a debug token

  1. Paste the debug token into Debug token. The field is masked.
  2. Click Exchange.

The result shows the App Check Token with a Copy button, its TTL (time to live, set by the app’s App Check settings), and the decoded claims. Send the token in the X-Firebase-AppCheck header:

curl -H "X-Firebase-AppCheck: $APP_CHECK_TOKEN" https://us-central1-<project>.cloudfunctions.net/hello

Checking the audience

The tab ends with a reminder to compare your server’s project with the aud claim. App Check tokens list the project by number and by ID, for example ["projects/316659987175","projects/fir-token-toolkit-demo"]. A backend configured for a different project rejects the token.

Saving the debug token

Each app keeps its own debug token, so switching apps switches tokens too. Like API keys, debug tokens are saved between launches only when remember API keys & debug tokens is ticked. Otherwise you paste it again after restarting.

When the exchange fails

API error (403): App attestation failed. almost always means the debug token is not registered for this App ID. See Troubleshooting for other errors.

Reading the results

Every tab presents tokens the same way.

The token box

The token appears in a read-only, scrollable box with its name (Custom Token, ID Token or App Check Token) and a Copy button above it. Copy puts the whole token on the clipboard. If the clipboard is unavailable, the error appears next to the button; you can still select the text in the box and copy it with Ctrl+C (⌘+C on macOS).

Decoded JWT claims

Click Decoded JWT claims to expand a table of everything in the token’s payload, sorted by name. Values are selectable for copying. Scroll the tab to reach the rest of a long table.

Timestamps are shown twice, as the raw Unix time and as UTC, for example 1791308692 (2026-10-06T17:44:52+00:00). That applies to iat (issued at), exp (expires) and auth_time (when the user signed in). Nested values, like the firebase claim in an ID token, are shown as compact JSON.

The table decodes the payload without checking the signature. It tells you what a token says, not whether a server will accept it.

Errors

When a request fails, the tab shows Error: and the message in red under its button. Problems with the top bar or the service account show in the status bar under the tabs instead, with a dismiss button. See Troubleshooting for what the messages mean.

Settings and storage

Everything the app remembers lives in one file, app.ron:

PlatformLocation
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

The file is written when the app closes and periodically while it runs.

What is saved

ValueSavedNotes
Profile namesAlways
Service-account pathAlwaysThe path only. The key file itself is never copied.
Project IDAlways
Active profile, last-used tabAlways
Window size and positionAlways
Each app’s name, type and App IDAlways
Android package and SHA-1, iOS bundle IDAlwaysPublic identifiers, included in every app build
Selected appAlways
Each app’s API keyOnly with remember API keys & debug tokensPlaintext
Each app’s App Check debug tokenOnly with remember API keys & debug tokensPlaintext
Service-account private keyNeverRe-read from the saved path at every launch
OAuth access tokensNeverHeld in memory, refreshed automatically
Minted custom, ID and App Check tokensNever

The remember API keys & debug tokens checkbox applies to every profile at once. When it is off, the app clears every app’s API key and debug token, in all profiles, when it starts and again every time it saves, so unticking it also removes values that were saved earlier. Clicking Load apps fetches the keys again.

If the service-account file has moved or been deleted, the app starts with no service account loaded and the status indicator shows ● not configured. Use Browse… to point the profile at the new location.

Resetting the app

Close the app and delete app.ron. The next launch starts with a single empty profile named Default.

Upgrading from 0.1.x

Version 0.1.x stored one API key, App ID and debug token per profile. The first launch of a newer version turns them into the profile’s first app, named after its type (for example Web app) and with its type taken from the App ID. If remember was off, 0.1.x saved none of the three, so the profile starts with one empty web app; Load apps fills in the project’s apps.

Upgrading from early versions

Versions before profiles existed stored a single set of fields at the top level of the file. The first launch of a newer version moves those values into a profile named Default; nothing needs to be done by hand.

Google endpoints

Every network request the app makes goes to a Google endpoint over TLS, and only when you click a button that needs it. There is no telemetry, analytics or update check. Opening a link from the About dialog hands that URL to your browser; nothing else leaves the app.

Action in the appRequestAuthenticated with
Generate on UID -> Custom TokenNone. The token is signed locally.—
Generate on UID -> ID Token, Exchange on Custom -> ID TokenPOST identitytoolkit.googleapis.com/v1/accounts:signInWithCustomTokenSelected app’s API key
Load users / RefreshGET identitytoolkit.googleapis.com/v1/projects/{project}/accounts:batchGet (1,000 per page, up to 5,000)OAuth access token
Lookup, Load currentPOST identitytoolkit.googleapis.com/v1/projects/{project}/accounts:lookupOAuth access token
Save, Clear all claimsPOST identitytoolkit.googleapis.com/v1/projects/{project}/accounts:update, then a lookup to read the result backOAuth access token
Exchange on App CheckPOST firebaseappcheck.googleapis.com/v1beta/projects/{project}/apps/{app}:exchangeDebugTokenSelected app’s API key
Load appsGET firebase.googleapis.com/v1beta1/projects/{project}:searchApps, then for each app GET …/webApps/{app}/config, …/androidApps/{app}/config and …/androidApps/{app}/sha, or …/iosApps/{app}/configOAuth access token

API keys and app identity

Requests authenticated with an API key send it as the key query parameter. For an Android or iOS app, the request also names the app, so that keys restricted to that app are accepted:

App typeHeaders
Webnone
AndroidX-Android-Package: <package>, X-Android-Cert: <SHA-1, 40 uppercase hex digits>
iOSX-Ios-Bundle-Identifier: <bundle ID>

A header is left out when its value is empty, and a SHA-1 that is not 40 hex digits is not sent.

OAuth access tokens

Calls marked OAuth access token first exchange a JWT, signed with the service-account key, at oauth2.googleapis.com/token. The token is requested with two scopes:

  • https://www.googleapis.com/auth/identitytoolkit
  • https://www.googleapis.com/auth/cloud-platform

It is cached in memory and refreshed when it is within about a minute of expiring. Switching profiles discards it.

cloud-platform is a broad scope. What the token can actually do is limited by the IAM roles granted to the service account, which is one more reason to use a development project’s key. See Security.

Troubleshooting

Messages appear in one of three places: the status bar under the tabs, the Users panel, or in red as Error: … under a tab’s button. Error text from Google is passed through unchanged, so search the message itself if it is not listed here.

The app does not open

If no graphics backend works, the app shows a dialog that begins “Firebase Token Toolkit could not start.” The app tries OpenGL first and then wgpu, which can fall back to a software renderer, so this almost always means a virtual machine or remote desktop session with no usable graphics at all. Enabling 3D acceleration for the VM usually fixes it.

On Linux, launching from a terminal shows the detail. A line like OpenGL backend unavailable (…); retrying with wgpu is informational; the app carries on with wgpu.

Service account

MessageCause and fix
Could not load service account: read service account file: <path>The file cannot be read. Check that it exists and that your user can read it.
Could not load service account: parse service account JSON: <path>The file is not valid JSON, or not a service-account key. Download a fresh key.
Could not load service account: service account JSON must contain client_email and private_keyThe JSON is some other kind of credential, such as a web app config. Use Generate new private key in the Firebase console.
parse RSA private key (must be PEM PKCS#8 / PKCS#1)The private_key field has been edited or mangled. Download a fresh key.
The file picker closed unexpectedlyOn Linux, the XDG desktop portal is missing or crashed. Install xdg-desktop-portal-gtk or your desktop’s portal.
● not configured after a restartThe saved key file has moved. Use Browse… to find it again.

Authentication with Google

MessageCause and fix
oauth2 token error (400): … invalid_grant …The key has been deleted or disabled in Google Cloud, or your system clock is off by several minutes. Check the clock, then generate a new key.
oauth2 token error (401): …The service account no longer exists. Generate a key for an active account.
POST oauth2 token (no further detail)The request never reached Google. Check your network connection and any proxy.

Users panel

MessageCause and fix
Load a service account and set Project ID to browse users.Load a key and make sure Project ID is filled in.
No user found for that queryLookup needs the whole value: a complete email (case does not matter), a phone number in full + country-code form, or an exact UID. To match part of a value, type into the search box without pressing Enter; that filters the users already loaded.
API error (403): …The service account lacks permission to read users, or the Identity Toolkit API is disabled for the project.
GET accounts:batchGetThe request never reached Google. Check your connection.

Tokens

MessageCause and fix
API key requiredThe selected app has no API key. Click Load apps, or paste the key.
API error (400): INVALID_CUSTOM_TOKEN : Invalid assertion format. 3 dot separated segments required.The pasted text is not a whole token. It usually lost characters while being copied.
API error (400): INVALID_CUSTOM_TOKEN … with other textThe token has expired (custom tokens last one hour) or is malformed. Generate a new one.
API error (400): CREDENTIAL_MISMATCHThe custom token was signed with a key from a different project than the API key belongs to. Check that the profile’s key and API key are from the same project.
API error (400): API key not valid. Please pass a valid API key.The API key is wrong or deleted. Copy it again from Project settings → General.
API error (403): Requests from this Android client application <empty> are blocked. (or the iOS equivalent)The key is restricted to an Android or iOS app, but the selected app is a different type, or its Package or Bundle ID is empty. Select the matching app, or fill in its identifiers.
API error (403): Requests from this Android client application dev.example.app are blocked.The package or SHA-1 does not match the key’s restriction. Check both against the key in Google Cloud Console → Credentials. A SHA-1 marked invalid in the top bar is not sent.
API error (403): Requests from this iOS client application <bundle> are blocked.The bundle ID does not match the key’s restriction.
API error (403): … are blocked. (other)The API key has restrictions that exclude the Identity Toolkit API or the App Check API. Loosen them in Google Cloud Console.
Invalid claims JSON: … / custom claims must be a JSON objectThe optional claims box must hold a JSON object, such as {"role":"admin"}, or be empty.
Paste a custom token firstThe Custom -> ID Token input is empty.

User Custom Claims

MessageCause and fix
Serialized claims are N bytes; Firebase limit is 1000 bytes.Firebase rejects claims over 1,000 bytes. Shorten keys or move data to your database.
Claims editor is empty (use 'Clear all claims' to wipe).Save with an empty editor is refused on purpose. To remove every claim, use Clear all claims.
Claims must be a JSON object.Top-level arrays, strings and numbers are not allowed.
User not foundThe user was deleted after you picked them. Refresh the Users panel.

App Check

MessageCause and fix
Debug token requiredPaste the debug token into the tab.
API error (403): App attestation failed.The debug token is not registered for this App ID. Check it under App Check → Manage debug tokens, and that it was registered for the same app as the App ID in the top bar.
API error (403): … with other textThe App Check API is not enabled for the project, or the API key’s restrictions exclude it.
API error (404): …The App ID does not exist in the project named in Project ID.

Load apps

MessageCause and fix
Loading apps failed: API error (403): …The service account may not read Firebase apps, or the Firebase Management API is disabled. Grant Firebase Viewer (roles/firebase.viewer), or add the app by hand with + Add app.
No apps found in this Firebase project.The project has no registered apps. Add one under Project settings → General → Your apps.
Loaded apps: … Some details are missing — …The list loaded, but one app’s config or certificates could not be read. That app is listed without its key; fill it in by hand.

Linux desktop issues

Browse… does nothing. The file chooser goes through an XDG desktop portal. Install xdg-desktop-portal-gtk (or your desktop’s portal) and log in again.

Copy shows copy failed: …. The clipboard needs X11 or XWayland. Under a pure Wayland session without XWayland, select the token text and copy it with Ctrl+C instead.

The Changelog and Security notes links in the About dialog point at the git tag matching the app’s version. A build from an untagged commit has no such tag, so the links 404. Release builds are not affected.

FAQ

Short answers to the questions that usually bring people here, with links to the full pages.

How do I get a Firebase ID token to test my API in Postman or curl?

Load your service-account key, click Load apps, pick a user in the Users panel, and click Generate on the UID -> ID Token tab. Click Copy and send the token as a bearer token:

curl -H "Authorization: Bearer <ID token>" https://localhost:8080/api/me

In Postman, choose Authorization → Bearer Token and paste it. The Quick start walks through it with screenshots.

How do I test a backend that verifies Firebase ID tokens?

The tokens the app produces are real ID tokens issued by Google for your project, so they pass verifyIdToken in the Firebase Admin SDKs and any other check against Google’s public keys. Generate one for the user you want to test as, and call your API with it. Add claims for a single token in the Custom claims box to test role checks without touching the user record.

How do I sign in as a specific user without their password?

The app signs a custom token for the user’s UID with your service-account key and exchanges it with Google, the same flow as createCustomToken followed by signInWithCustomToken. You never need the user’s password, which is also why the service-account key must be kept safe. See Security.

How do I set Firebase custom claims without writing code?

Use the User Custom Claims tab. Load current shows the user’s claims as JSON, you edit them, and Save writes them to the user record, the same as setCustomUserClaims in the Admin SDK. A counter keeps you under Firebase’s 1,000-byte limit.

Why don’t my new custom claims show up in the ID token?

Tokens issued before the change keep the old claims until they expire, about an hour later. Generate a new token on the UID -> ID Token tab, or force a refresh on the client, for example getIdToken(true). See When changes take effect.

How do I get a Firebase App Check token for testing?

Register a debug token for your app under App Check → Manage debug tokens in the Firebase console, then paste it into the App Check tab and click Exchange. Send the result in the X-Firebase-AppCheck header. This works for web, Android and iOS apps.

Can I use an API key restricted to an Android or iOS app?

Yes. Select the Android or iOS app in the top bar and the app sends its package name and SHA-1, or bundle ID, with each request, as the Firebase SDKs do. See API keys restricted to an app.

How do I decode a Firebase JWT?

Every token the app shows has a Decoded JWT claims table underneath, with iat, exp and auth_time converted to readable UTC times. The table shows what a token says; it does not verify the signature. See Reading the results.

How long do the tokens last?

Custom tokens and ID tokens last one hour. An App Check token lasts for the time to live set in your App Check settings, shown as TTL under the token. When a token expires, generate a new one.

Does it work with the Firebase Auth emulator?

No. The app talks to Google’s production endpoints for your project, so it needs a real Firebase project. Use a development project rather than production; see Preparing your Firebase project.

Which platforms does it run on?

Linux (x86_64, glibc 2.35 or newer), Windows (x86_64) and macOS 11 or newer on Apple Silicon or Intel. See Installation.

Is it free?

Yes. It is open source under the MIT licence, and its source is on GitHub.

Security

Firebase Token Toolkit loads a service-account private key and mints real, signed tokens with it. The app is about as sensitive as the key file itself. SECURITY.md in the repository is the authoritative description; this page is the short version for day-to-day use.

What the app keeps

  • The private key is read from the file you choose and held in memory. It is never copied into the settings file.
  • OAuth access tokens and every token shown on screen live in memory only.
  • API keys and App Check debug tokens are written to disk, in plaintext, only when remember API keys & debug tokens is ticked. App IDs, package names, SHA-1s and bundle IDs are always saved; they are public, since every build of your app contains them. See Settings and storage.

Habits worth keeping

  • Point the app at a development project. A service-account key can mint a token for any user in its project.
  • Treat the window like a terminal full of secrets. An ID token on screen signs in as that user until it expires, usually an hour later. Be careful when screen sharing.
  • The Users panel shows personal data. Emails, phone numbers and display names come straight from Firebase Authentication.
  • Custom claims are permanent until changed. Save on the User Custom Claims tab writes to the user record, not to one token, so every future ID token for that user carries the claims.

Reporting a vulnerability

Use GitHub’s private vulnerability reporting rather than opening a public issue.

Building and contributing

Build from source

You need Rust 1.90 or newer.

git clone https://github.com/smaranjit/firebase-token-toolkit
cd firebase-token-toolkit
cargo build --release
# the binary is target/release/firebase-token-toolkit

Linux also needs the windowing and clipboard development headers:

sudo apt install -y \
  libxkbcommon-dev libxkbcommon-x11-dev libwayland-dev libgl1-mesa-dev \
  libx11-dev libxrandr-dev libxi-dev libxcursor-dev \
  libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev pkg-config

Windows needs the MSVC toolchain from Visual Studio Build Tools, and macOS needs the Xcode command line tools. TLS goes through rustls, so no platform needs OpenSSL.

Contributing

Issues and pull requests are welcome. CONTRIBUTING.md covers the checks CI runs, the project layout, building release archives and cutting a release.

Editing this guide

The guide is an mdBook in the docs/ folder of the repository. To preview changes locally:

mdbook serve docs --open

Every page has an edit icon in the top-right corner that opens it on GitHub. Changes merged to main are published automatically.