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:
- Go to Firebase Console > Project Settings > General
- Scroll down to "Your apps" section
- 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:
- Sign-in Methods: Only Google sign-in enabled
- Authorized domains: localhost, admin.promptable.ai
- Access Control: Allowlist configured with Promptable internal team emails only
To manage the allowlist:
- Go to Firebase Console > Authentication > Users
- Pre-authorize users by adding their @promptable.ai emails
- 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
-
Environment Variables:
- Use GitHub Secrets for CI/CD
- Never commit
.envfiles - Consider using Firebase SDK auto-configuration
-
Security:
- Enable Firebase App Check
- Configure CORS properly
- Use Security Rules extensively
- Monitor Firebase Auth logs
-
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 -
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
- IP Allowlisting: Consider restricting access by IP if admin users are from known locations
- 2FA: Implement two-factor authentication for admin accounts
- Session Management: Set appropriate session timeout
- Audit Logging: Track admin actions in Firestore
- Rate Limiting: Implement rate limiting on auth endpoints
- CAPTCHA: Add reCAPTCHA for login forms to prevent brute force attacks