Skip to main content

Firebase Auth Setup Guide for admin.promptable.ai

Current OWL Site Firebase Setup (Reference)

The OWL documentation site (owl.promptable.ai) uses a minimal Firebase Hosting setup:

Firebase Project Structure

  • Project ID: owl-website-88e2b
  • Hosting Only: No authentication, database, or functions
  • Static Site: Docusaurus build output served from build/ directory
  • SPA Configuration: All routes rewrite to /index.html

Deployment Process

npm run build
firebase deploy --only hosting

Current Setup for admin.promptable.ai

1. Firebase Project Setup ✅

Project Details:

  • Project Name: admin-promptable-ai
  • Status: Already created and configured
  • Authentication: Google Auth enabled with allowlist
  • Access Control: Restricted to Promptable internal team members only

Initial Setup (Already Completed)

The Firebase project has been created with the following configuration:

  • Hosting: Configured for Firebase Hosting
  • Authentication: Google Authentication enabled
  • Allowlist: Only @promptable.ai email addresses can access
  • Project ID: admin-promptable-ai

For local development setup:

# Install Firebase CLI if not already installed
npm install -g firebase-tools

# Login to Firebase
firebase login

# Initialize in your admin repo (select existing project)
firebase init

When running firebase init, select:

  • Existing project: admin-promptable-ai
  • Public directory: build (for Docusaurus/React)
  • Single-page app: Yes (rewrite all URLs to /index.html)

2. Firebase Authentication Implementation

Install Firebase SDK

npm install firebase

Create Firebase Configuration

Create src/firebase/config.ts:

import { initializeApp } from 'firebase/app';
import { getAuth } from 'firebase/auth';

const firebaseConfig = {
apiKey: process.env.REACT_APP_FIREBASE_API_KEY,
authDomain: process.env.REACT_APP_FIREBASE_AUTH_DOMAIN,
projectId: process.env.REACT_APP_FIREBASE_PROJECT_ID,
storageBucket: process.env.REACT_APP_FIREBASE_STORAGE_BUCKET,
messagingSenderId: process.env.REACT_APP_FIREBASE_MESSAGING_SENDER_ID,
appId: process.env.REACT_APP_FIREBASE_APP_ID
};

const app = initializeApp(firebaseConfig);
export const auth = getAuth(app);
export default app;

Environment Variables

Create .env.local (add to .gitignore):

REACT_APP_FIREBASE_API_KEY=your-api-key
REACT_APP_FIREBASE_AUTH_DOMAIN=admin-promptable-ai.firebaseapp.com
REACT_APP_FIREBASE_PROJECT_ID=admin-promptable-ai
REACT_APP_FIREBASE_STORAGE_BUCKET=admin-promptable-ai.appspot.com
REACT_APP_FIREBASE_MESSAGING_SENDER_ID=your-sender-id
REACT_APP_FIREBASE_APP_ID=your-app-id

Note: Get the actual API key, sender ID, and app ID from the Firebase Console:

  1. Go to Firebase Console > Project Settings > General
  2. Scroll down to "Your apps" section
  3. Copy the configuration values

3. Authentication Context & Provider

Create src/contexts/AuthContext.tsx:

import React, { createContext, useContext, useEffect, useState } from 'react';
import {
User,
signInWithEmailAndPassword,
createUserWithEmailAndPassword,
signOut,
onAuthStateChanged,
signInWithPopup,
GoogleAuthProvider
} from 'firebase/auth';
import { auth } from '../firebase/config';

interface AuthContextType {
currentUser: User | null;
login: (email: string, password: string) => Promise<void>;
register: (email: string, password: string) => Promise<void>;
logout: () => Promise<void>;
loginWithGoogle: () => Promise<void>;
loading: boolean;
}

const AuthContext = createContext<AuthContextType | undefined>(undefined);

export function useAuth() {
const context = useContext(AuthContext);
if (!context) {
throw new Error('useAuth must be used within an AuthProvider');
}
return context;
}

export function AuthProvider({ children }: { children: React.ReactNode }) {
const [currentUser, setCurrentUser] = useState<User | null>(null);
const [loading, setLoading] = useState(true);

useEffect(() => {
const unsubscribe = onAuthStateChanged(auth, (user) => {
setCurrentUser(user);
setLoading(false);
});

return unsubscribe;
}, []);

const login = async (email: string, password: string) => {
await signInWithEmailAndPassword(auth, email, password);
};

const register = async (email: string, password: string) => {
await createUserWithEmailAndPassword(auth, email, password);
};

const logout = async () => {
await signOut(auth);
};

const loginWithGoogle = async () => {
const provider = new GoogleAuthProvider();
await signInWithPopup(auth, provider);
};

const value: AuthContextType = {
currentUser,
login,
register,
logout,
loginWithGoogle,
loading
};

return (
<AuthContext.Provider value={value}>
{!loading && children}
</AuthContext.Provider>
);
}

4. Protected Routes Component

Create src/components/ProtectedRoute.tsx:

import React from 'react';
import { Navigate } from '@docusaurus/router';
import { useAuth } from '../contexts/AuthContext';

interface ProtectedRouteProps {
children: React.ReactNode;
}

export default function ProtectedRoute({ children }: ProtectedRouteProps) {
const { currentUser } = useAuth();

if (!currentUser) {
return <Navigate to="/login" />;
}

return <>{children}</>;
}

5. Wrap Docusaurus App with Auth Provider

Modify src/theme/Root.tsx (create if doesn't exist):

import React from 'react';
import { AuthProvider } from '../contexts/AuthContext';

export default function Root({ children }) {
return <AuthProvider>{children}</AuthProvider>;
}

6. Create Login Page

Create src/pages/login.tsx:

import React, { useState } from 'react';
import Layout from '@theme/Layout';
import { useAuth } from '../contexts/AuthContext';
import { useHistory } from '@docusaurus/router';

export default function Login() {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [error, setError] = useState('');
const { login, loginWithGoogle } = useAuth();
const history = useHistory();

const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
try {
setError('');
await login(email, password);
history.push('/');
} catch (error) {
setError('Failed to log in');
}
};

const handleGoogleLogin = async () => {
try {
setError('');
await loginWithGoogle();
history.push('/');
} catch (error) {
setError('Failed to log in with Google');
}
};

return (
<Layout title="Login">
<div className="container margin-vert--lg">
<div className="row">
<div className="col col--4 col--offset-4">
<h1>Admin Login</h1>
{error && <div className="alert alert--danger">{error}</div>}
<form onSubmit={handleSubmit}>
<div className="margin-bottom--md">
<input
type="email"
placeholder="Email"
value={email}
onChange={(e) => setEmail(e.target.value)}
required
className="navbar__search-input"
/>
</div>
<div className="margin-bottom--md">
<input
type="password"
placeholder="Password"
value={password}
onChange={(e) => setPassword(e.target.value)}
required
className="navbar__search-input"
/>
</div>
<button type="submit" className="button button--primary button--block">
Login
</button>
</form>
<div className="margin-top--md">
<button
onClick={handleGoogleLogin}
className="button button--secondary button--block"
>
Login with Google
</button>
</div>
</div>
</div>
</div>
</Layout>
);
}

7. Firebase Security Rules

Current Configuration in Firebase Console > Authentication:

  1. Sign-in Methods: Only Google sign-in enabled
  2. Authorized domains: localhost, admin.promptable.ai
  3. Access Control: Allowlist configured with Promptable internal team emails only

To manage the allowlist:

  1. Go to Firebase Console > Authentication > Users
  2. Pre-authorize users by adding their @promptable.ai emails
  3. Or implement domain-based restrictions in your auth logic

For Firestore (if needed):

rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if request.auth != null;
}
}
}

8. Protect Admin Routes

For protecting docs or specific pages, wrap them with ProtectedRoute:

// In any page that needs protection
import ProtectedRoute from '../components/ProtectedRoute';

export default function AdminDashboard() {
return (
<ProtectedRoute>
<Layout title="Admin Dashboard">
{/* Admin content */}
</Layout>
</ProtectedRoute>
);
}

9. User Management Features

Add user role management in Firebase Console or programmatically:

// Set custom claims (requires Firebase Admin SDK on server)
await admin.auth().setCustomUserClaims(uid, { admin: true });

// Check claims in app
const idTokenResult = await currentUser.getIdTokenResult();
const isAdmin = idTokenResult.claims.admin;

10. Deployment Considerations

  1. Environment Variables:

    • Use GitHub Secrets for CI/CD
    • Never commit .env files
    • Consider using Firebase SDK auto-configuration
  2. Security:

    • Enable Firebase App Check
    • Configure CORS properly
    • Use Security Rules extensively
    • Monitor Firebase Auth logs
  3. Private Repository Setup:

    # In GitHub repo settings
    # Settings > Manage access > Make repository private

    # For deployment, add secrets:
    # Settings > Secrets > Actions
    # Add FIREBASE_SERVICE_ACCOUNT_ADMIN_PROMPTABLE
  4. GitHub Actions Deployment:

    name: Deploy to Firebase Hosting
    on:
    push:
    branches: [ main ]

    jobs:
    deploy:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - uses: actions/setup-node@v3
    with:
    node-version: '20'
    - run: npm ci
    - run: npm run build
    env:
    REACT_APP_FIREBASE_API_KEY: ${{ secrets.FIREBASE_API_KEY }}
    # ... other env vars
    - uses: FirebaseExtended/action-hosting-deploy@v0
    with:
    repoToken: '${{ secrets.GITHUB_TOKEN }}'
    firebaseServiceAccount: '${{ secrets.FIREBASE_SERVICE_ACCOUNT }}'
    channelId: live
    projectId: admin-promptable

Implementation Checklist

  • Create new Firebase project for admin site (admin-promptable-ai)
  • Enable Authentication in Firebase Console
  • Set up Google authentication method
  • Configure allowlist for Promptable internal team
  • Configure environment variables locally
  • Implement AuthContext and provider
  • Create login page (Google sign-in only)
  • Protect admin routes
  • Implement domain-based access control in code
  • Configure deployment pipeline
  • Test authentication flow with team members
  • Set up proper session management
  • Enable Firebase App Check for security
  • Monitor authentication analytics

Additional Security Recommendations

  1. IP Allowlisting: Consider restricting access by IP if admin users are from known locations
  2. 2FA: Implement two-factor authentication for admin accounts
  3. Session Management: Set appropriate session timeout
  4. Audit Logging: Track admin actions in Firestore
  5. Rate Limiting: Implement rate limiting on auth endpoints
  6. CAPTCHA: Add reCAPTCHA for login forms to prevent brute force attacks