Fireguards are hot, but not enough to burn. As long as you got your mitts on.
Firemitt is a client-side integration package for Fireguard, a Firebase authentication middleman app. It handles the full lifecycle of an auth flow: opening the Fireguard window (popup or iframe), passing configuration, and resolving or rejecting based on the authentication result.
It is particularly useful for browser extensions and web apps operating under Manifest V3 restrictions, where direct Firebase SDK usage is limited or blocked.
FiremittHelper.auth opens a Fireguard popup window, manages the auth handshake, and returns a promise that resolves with the token on success or rejects on failure.mode: "iframe". Provide an existing iframe element or a container element and Firemitt manages the lifecycle.provider field.ConfigHelper validates and normalizes Fireguard options before they are used, catching missing or malformed values early.pnpm add @eoussama/firemitt
FiremittHelper.auth is the main entry point. It opens a Fireguard popup window, passes your configuration to it, and returns a promise that resolves with the auth token on success.
Important: browsers only allow popups opened from a user gesture. Call
FiremittHelper.authsynchronously inside your click handler (do notawaitanything before it), otherwise the promise rejects with aPopupBlockedError.
import { FiremittHelper } from "@eoussama/firemitt";
const options = {
// URL of the Fireguard instance (use the hosted one or a self-hosted deployment)
url: "https://ouss.es/fireguard/",
// Optional: position of the popup window (defaults to centered on the current window, 50px from the top)
pos: {
x: window.screenX + (window.outerWidth - 450) / 2,
y: 50
},
// Optional: dimensions of the popup window (defaults to 450x260)
dim: {
width: 450,
height: 260
},
config: {
name: "My App Name",
// Optional: authentication provider (default: "google")
provider: "google",
// Optional: absolute URL to your app's logo
logo: "https://url/to/your/logo/image",
// Optional: custom theme colors
theme: {
text: "#1a3544",
primary: "#ffe536",
secondary: "#1a3544",
background: "#ffffff"
},
// Your web app's Firebase configuration
firebase: {
appId: "",
apiKey: "",
projectId: "",
authDomain: ""
}
}
};
button.addEventListener("click", async () => {
try {
const token = await FiremittHelper.auth(options);
// Use the token, e.g. to sign in to Firebase in your app (see below).
await onSignedIn(token);
}
catch (error) {
console.error("Authentication failed:", error);
}
});
Chrome extensions: do not call
auth()from the toolbar (action) popup. It closes as soon as the Fireguard window takes focus, which destroys the page waiting for the result. Call it from an options page, a tab or a side panel instead. Iframe mode does not help there either, since Fireguard opens the provider's sign-in popup, which closes the toolbar popup as well.
Set mode: "iframe" and provide either a container (Firemitt creates the iframe, sizes it with dim, and removes it once the session settles) or an existing element (Firemitt loads Fireguard into it but never resizes or removes it).
// Auto-created iframe inside a container element
FiremittHelper.auth({
url: "https://ouss.es/fireguard/",
mode: "iframe",
iframe: { container: document.getElementById("auth-container")! },
config: { name: "My App", firebase: { /* ... */ } }
});
// Existing iframe element
FiremittHelper.auth({
url: "https://ouss.es/fireguard/",
mode: "iframe",
iframe: { element: document.getElementById("auth-frame") as HTMLIFrameElement },
config: { name: "My App", firebase: { /* ... */ } }
});
Fireguard opens the provider's sign-in popup from inside the iframe, so the iframe must not be sandboxed (the sign-in popup would inherit the sandbox, unless
allow-popups-to-escape-sandboxis set along withallow-scripts allow-same-origin allow-popups).
You can point
urlat the hosted Fireguard instance (https://ouss.es/fireguard/) or your own self-hosted deployment.
Note: Firebase only allows sign-in popups from authorized domains. Add the domain of the Fireguard instance you use (
ouss.esfor the hosted one, or your own domain when self-hosting) to the authorized domains list in the Firebase Console under Authentication → Settings → Authorized domains. Skipping this step makes the authentication fail withauth/unauthorized-domain.
| Error | When |
|---|---|
InvalidURLError, InvalidDimError, InvalidAppNameError, InvalidFirebaseConfigError, InvalidIframeError |
Thrown synchronously by auth() when the options are invalid. |
PopupBlockedError |
The promise rejects when the browser refused to open the popup. |
AuthFailedError |
The promise rejects when Fireguard reports a failure. It keeps the remote type, name and message, the code when the Fireguard instance sends one (e.g. a Firebase auth/* code, Fireguard 0.1.4+), and the raw payload as cause. A success reported without a token also rejects with an AuthFailedError. |
Error("The authentication window was closed.") |
The promise rejects when the user closes the Fireguard window. |
Error("A new authentication session was started.") |
The promise rejects when another auth() call replaces the session. The previous popup is closed, the previous auto-created iframe is removed. |
auth() resolves with the OAuth token returned by the provider: the ID token when the provider issues one (Google, Apple, Microsoft, Yahoo, OIDC providers), the access token otherwise (GitHub, Facebook, Twitter). For example, to sign the user in to Firebase in your app:
import { getAuth, GithubAuthProvider, GoogleAuthProvider, signInWithCredential } from "firebase/auth";
await signInWithCredential(getAuth(), GoogleAuthProvider.credential(token)); // Google: ID token
await signInWithCredential(getAuth(), GithubAuthProvider.credential(token)); // GitHub: access token
Check the Firebase documentation to know whether signInWithCredential supports your provider. Twitter credentials also require the OAuth secret, which Fireguard does not return. SAML providers return no OAuth token, so they are not supported yet.
TFiremittOptions| Property | Type | Required | Default | Description |
|---|---|---|---|---|
url |
string |
✓ | URL of the Fireguard instance to open (http or https). |
|
mode |
"popup" | "iframe" |
"popup" |
Authentication mode. | |
iframe |
TIframeOptions |
In iframe mode | Provide either an existing element or a container. | |
pos |
Partial<TPos> |
Centered on the current window, 50px from the top | Position of the popup window on screen. Ignored in iframe mode. | |
dim |
Partial<TDim> |
450 × 260 |
Dimensions of the popup or auto-created iframe. | |
config |
Partial<TFireguardOptions> |
✓ | Fireguard configuration passed to the auth window. |
TIframeOptions| Property | Type | Required | Description |
|---|---|---|---|
element |
HTMLIFrameElement |
✓ (or container) |
Existing iframe element to load Fireguard into. |
container |
HTMLElement |
✓ (or element) |
Container element where Firemitt creates and appends an iframe automatically. |
TPos| Property | Type | Required | Description |
|---|---|---|---|
x |
number |
Horizontal position of the popup window in pixels. | |
y |
number |
Vertical position of the popup window in pixels. |
TDim| Property | Type | Required | Description |
|---|---|---|---|
width |
number |
Width of the popup or auto-created iframe in pixels, greater than zero. | |
height |
number |
Height of the popup or auto-created iframe in pixels, greater than zero. |
TFireguardOptions| Property | Type | Required | Default | Description |
|---|---|---|---|---|
name |
string |
✓ | Display name of your application shown in the Fireguard UI. | |
firebase |
TFirebaseConfig |
✓ | Firebase project configuration used to initialize authentication. | |
logo |
string |
Absolute URL to your app's logo image displayed in the Fireguard UI. | ||
provider |
string |
"google" |
Authentication provider to use, see EProvider. Built-in values are case-insensitive. Custom oidc.<id> identifiers are also accepted. |
|
theme |
Partial<TTheme> |
See TTheme |
Custom colors applied to the Fireguard UI. |
TTheme| Property | Type | Required | Default | Description |
|---|---|---|---|---|
text |
string |
#1a3544 |
Color applied to text elements. | |
primary |
string |
#ffe536 |
Primary accent color. | |
secondary |
string |
#1a3544 |
Secondary accent color. | |
background |
string |
#ffffff |
Page background color. |
EProvider| Value | Provider |
|---|---|
"google" |
|
"github" |
GitHub |
"facebook" |
|
"twitter" |
Twitter / X |
"microsoft" |
Microsoft |
"apple" |
Apple |
"yahoo" |
Yahoo |
TFirebaseConfig| Property | Type | Required | Description |
|---|---|---|---|
appId |
string |
✓ | Unique identifier for the Firebase app. |
apiKey |
string |
✓ | API key for authenticating Firebase requests. |
projectId |
string |
✓ | Globally unique identifier for the Firebase project. |
authDomain |
string |
✓ | Domain used by Firebase Authentication. |
measurementId |
string |
Google Analytics measurement ID. | |
storageBucket |
string |
Cloud Storage bucket name for Firebase Storage. | |
messagingSenderId |
string |
Sender ID for Firebase Cloud Messaging. |
Full API reference is available in the docs.
window.open keeps the opener relationship on purpose: Fireguard needs it to send the result back.An interactive playground runs Firemitt (from src, no build needed) against a Fireguard instance without writing any code:
To run it, copy .env.example to .env to prefill the Fireguard URL and your Firebase credentials (or type them in the form, they are remembered in your browser), then:
pnpm playground # http://localhost:5174
To test a local Fireguard, start it next to Firemitt (pnpm dev in the Fireguard repository, on http://localhost:5173) and pick the "Local dev" URL. Ctrl + Enter runs the selected scenario.
Contributions are welcome. Please read the contributing guidelines and code of conduct before opening a pull request.