Use Firebase Authentication with Strapi v5 - without building custom auth logic.
Firebase handles user authentication (Google, Apple, Phone, Email, Magic Link). This plugin bridges Firebase to Strapi by verifying tokens, automatically creating/syncing users, and returning Strapi JWTs for API access. Your users authenticate once with Firebase and get full access to your Strapi content based on roles and permissions.
sequenceDiagram
participant App as Your App
participant Firebase as Firebase Auth
participant Strapi as Strapi + Plugin
rect rgb(240, 248, 255)
Note over App,Firebase: Authentication
App->>Firebase: 1. Sign in (Google, Apple, Phone, Email...)
Firebase-->>App: 2. Returns Firebase ID Token
end
rect rgb(240, 255, 240)
Note over App,Strapi: Token Exchange
App->>Strapi: 3. POST /api/firebase-authentication { idToken }
Strapi->>Firebase: 4. Verify token
Firebase-->>Strapi: 5. Token valid
Note over Strapi: 6. Find or create Strapi user
Strapi-->>App: 7. Returns { user, jwt }
end
rect rgb(255, 250, 240)
Note over App,Strapi: API Access
App->>Strapi: 8. GET /api/content (Bearer jwt)
Strapi-->>App: 9. Protected data
end
Summary:
- Steps 1-2: User authenticates with Firebase (you handle this with Firebase SDK)
- Steps 3-7: You send the Firebase token to this plugin, it verifies with Firebase, finds or creates a Strapi user, and returns a Strapi JWT
- Steps 8-9: You use the Strapi JWT for all API calls to access protected content
-
🔐 Multi-Provider Auth - Support for Google, Apple, Email/Password, Phone, and Magic Link. All providers are verified server-side via Firebase Admin SDK and mapped to a single Strapi user using Firebase UID as the primary link. User signs in with Google on mobile, later with Apple on web - same Strapi user, same roles and permissions.
-
🔄 Auto User Sync - On first authentication, the plugin automatically creates a Strapi user with the default
authenticatedrole. Existing users are matched by Firebase UID first, then by email, then by phone number. Profile data (name, email, phone) is synced from the Firebase token. No manual user creation needed - scales to thousands of users. -
📱 Phone-Only Auth - For apps where email isn't required (common in emerging markets), the plugin generates unique placeholder emails using configurable patterns with tokens:
{randomString},{phoneNumber},{timestamp}. Example:{randomString}@phone-user.localbecomesa1b2c3d4@phone-user.local. Phone users get full access to Strapi's permission system. -
🔑 Password Reset - Two flows available:
POST /forgotPasswordsends a branded reset email via your Strapi email provider (SendGrid, Mailgun, etc.), andPOST /resetPasswordallows authenticated password changes. Includes customizable email templates, configurable reset URLs, regex password validation, and optional Firebase custom tokens for auto-login after reset. -
✨ Magic Link - Passwordless authentication via
POST /requestMagicLink. Generates a secure one-time JWT token with configurable expiry (1-72 hours), sends via your Strapi email provider, and returns a Strapi JWT on verification. Tokens are invalidated after use. Perfect for B2B apps where users prefer "email me a login link" over passwords. -
🛡️ Encrypted Config - Firebase service account JSON (contains private keys) is encrypted with AES-256 using your
FIREBASE_JSON_ENCRYPTION_KEYbefore storing in the database. Decrypted only in memory at runtime - never exposed in API responses, logs, or database backups. Meets enterprise security requirements. -
📊 Activity Logging - Tracks all authentication events with full context: user ID, Firebase UID, action type (login, token exchange, password reset, account deletion), IP address, and timestamp. Automatic cleanup via
FIREBASE_ACTIVITY_LOG_RETENTION_DAYS. Essential for security audits, debugging auth issues, and compliance requirements. -
🎛️ Admin Panel - Full Firebase user management UI integrated into Strapi admin at Plugins > Firebase Authentication. Search users by email/phone/UID, view linked Strapi accounts, edit user details, trigger password reset emails, send verification emails, and delete users from Firebase, Strapi, or both. No need to switch to Firebase Console.
yarn add strapi-plugin-firebase-authentication
# or
npm install strapi-plugin-firebase-authenticationCreate or update config/plugins.js:
module.exports = () => ({
"firebase-authentication": {
enabled: true,
config: {
FIREBASE_JSON_ENCRYPTION_KEY: process.env.FIREBASE_JSON_ENCRYPTION_KEY,
},
},
});Add to .env:
# Generate with: node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
FIREBASE_JSON_ENCRYPTION_KEY=your-32-character-minimum-key-hereyarn build && yarn develop- Go to Firebase Console → Project Settings → Service Accounts
- Click Generate New Private Key (downloads JSON)
- In Strapi: Settings → Firebase Authentication → Upload Configuration
- Restart Strapi after uploading
Settings → Users & Permissions → Roles → Public
Enable: firebase-authentication → authenticate ✓
| Method | Endpoint | Purpose |
|---|---|---|
| POST | /api/firebase-authentication |
Exchange Firebase token for Strapi JWT |
| POST | /api/firebase-authentication/emailLogin |
Direct email/password login |
| POST | /api/firebase-authentication/forgotPassword |
Request password reset email |
| POST | /api/firebase-authentication/requestMagicLink |
Request passwordless login link |
| GET | /api/firebase-authentication/config |
Get public configuration |
POST /api/firebase-authentication
Content-Type: application/json
{
"idToken": "firebase-id-token-here",
"profileMetaData": { // Optional
"firstName": "John",
"lastName": "Doe"
}
}Response:
{
"user": {
"id": 1,
"documentId": "abc123",
"email": "user@example.com",
"username": "user"
},
"jwt": "strapi-jwt-token"
}import { getAuth } from "firebase/auth";
// After Firebase sign-in
const auth = getAuth();
const idToken = await auth.currentUser.getIdToken();
// Exchange for Strapi JWT
const response = await fetch("https://your-api.com/api/firebase-authentication", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ idToken }),
});
const { user, jwt } = await response.json();
// Use JWT for Strapi API calls
const content = await fetch("https://your-api.com/api/articles", {
headers: { Authorization: `Bearer ${jwt}` },
});module.exports = () => ({
"firebase-authentication": {
enabled: true,
config: {
// Required: Key used to encrypt Firebase credentials (min 32 characters)
FIREBASE_JSON_ENCRYPTION_KEY: process.env.FIREBASE_JSON_ENCRYPTION_KEY,
// Optional: Require email for all users (default: false)
// When false, phone-only users get auto-generated emails
emailRequired: false,
// Optional: Email pattern for phone-only users
// Tokens: {randomString}, {phoneNumber}, {timestamp}
emailPattern: "{randomString}@phone-user.firebase.local",
// Optional: Days to keep activity logs (default: null = forever)
activityLogRetentionDays: 90,
},
},
});| Variable | Required | Description |
|---|---|---|
FIREBASE_JSON_ENCRYPTION_KEY |
Yes | AES encryption key for Firebase credentials. Minimum 32 characters. Generate with: node -e "console.log(require('crypto').randomBytes(32).toString('hex'))" |
FIREBASE_EMAIL_REQUIRED |
No | Set to true to require email for all users. Default: false |
FIREBASE_ACTIVITY_LOG_RETENTION_DAYS |
No | Auto-delete logs older than N days. Default: null (keep forever) |
Configure in Settings → Firebase Authentication:
General
| Setting | Default | Description |
|---|---|---|
| Firebase Web API Key | - | Required for emailLogin endpoint. Get from Firebase Console → Project Settings → General |
Password Settings
| Setting | Default | Description |
|---|---|---|
| Password Requirements Regex | ^.{6,}$ |
Regex pattern for password validation (default: 6+ chars) |
| Password Requirements Message | "Password must be at least 6 characters long" | Error message shown when password doesn't match regex |
| Password Reset URL | http://localhost:3000/reset-password |
URL where users land after resetting password |
| Password Reset Email Subject | "Reset Your Password" | Subject line for password reset emails |
| Include Credentials in Reset Link | false |
Include Firebase custom token for auto-login after reset |
Magic Link (Passwordless)
| Setting | Default | Description |
|---|---|---|
| Enable Magic Link | false |
Toggle passwordless email authentication |
| Magic Link URL | http://localhost:1338/verify-magic-link.html |
Landing page for magic link clicks |
| Magic Link Email Subject | "Sign in to Your Application" | Subject line for magic link emails |
| Magic Link Expiry Hours | 1 |
Token validity (1-72 hours) |
Email Verification
| Setting | Default | Description |
|---|---|---|
| Email Verification URL | http://localhost:3000/verify-email |
URL for email verification redirect |
| Email Verification Subject | "Verify Your Email" | Subject line for verification emails |
| Include Credentials in Verification Link | false |
Include Firebase custom token for auto-login after verification |
The service account JSON (uploaded via admin panel) should contain:
{
"type": "service_account",
"project_id": "your-project-id",
"private_key_id": "...",
"private_key": "-----BEGIN PRIVATE KEY-----\n...",
"client_email": "firebase-adminsdk-xxxxx@your-project.iam.gserviceaccount.com",
"client_id": "...",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token"
}Get this from: Firebase Console → Project Settings → Service Accounts → Generate New Private Key
Access at Plugins → Firebase Authentication:
- View and search Firebase users
- Edit user details
- Delete users (from Firebase, Strapi, or both)
- Send password reset emails
- View activity logs
Let Strapi administrators sign in to /admin with Firebase (Google or email/password) instead of a Strapi password. Works on Strapi Community Edition; no SSO license needed.
Requires Strapi 5.24.0 or newer (the plugin detects this at runtime and answers 503 on older versions).
- Admin opens
https://<your-api-host>/api/firebase-authentication/admin-login. - Signs in with Firebase on that page.
- The plugin verifies the Firebase ID token, checks the allowlist or the
strapiAdmincustom claim, finds (or creates) the Strapi admin by email, and mints a normal Strapi admin session. - The browser lands in
/admin, logged in. Session renewal and logout work exactly as with a password login. With "Remember me" off, the access token is kept only for the browser session, like Strapi's own login.
Settings live only in config/plugins.ts because they decide who can become an administrator.
// config/plugins.ts
export default ({ env }) => ({
"firebase-authentication": {
enabled: true,
config: {
firebaseJsonEncryptionKey: env("FIREBASE_JSON_ENCRYPTION_KEY"),
adminLogin: {
enabled: env.bool("FIREBASE_ADMIN_LOGIN_ENABLED", false),
allowedEmails: ["cto@example.com"], // optional, exact emails
allowedDomains: ["example.com"], // optional, email domains
autoCreateRole: "strapi-editor", // optional; omit to require pre-existing admins
},
},
},
});| Key | Default | Meaning |
|---|---|---|
enabled |
false |
Turns the page and the endpoint on. Off returns 404. |
allowedEmails |
[] |
Exact emails allowed to log in (case-insensitive). |
allowedDomains |
[] |
Email domains allowed to log in (case-insensitive). |
autoCreateRole |
null |
Role code (for example strapi-editor, strapi-author, strapi-super-admin) given to admins created on first login. null means the admin must already exist. |
A Firebase user is allowed when the email is verified and either it is allowlisted (email or domain) or the token carries a truthy custom claim named strapiAdmin:
await admin.auth().setCustomUserClaims(uid, { strapiAdmin: true });- Enable the sign-in providers you want (Google, Email/Password) in Firebase Console > Authentication > Sign-in method.
- Add your API host (for example
api.example.com) to Firebase Console > Authentication > Settings > Authorized domains. Google sign-in fails without it. - Set the Web API key in the plugin settings (Settings > Firebase Authentication). The sign-in page reads it from the public config endpoint.
- Feature is off by default. Enabling it with an empty allowlist means only the
strapiAdminclaim grants access; the plugin logs a warning at boot. - All 403 denials return the same message, so the endpoint cannot be used to find out which emails have admin accounts. The exact reason is written to the plugin activity log (
admin_login_denied). - The endpoint is rate limited to 20 attempts per 5 minutes, keyed on the address of the machine holding the connection. Forwarded headers are deliberately ignored here because a caller can set them. Behind a reverse proxy every client shares the proxy's address, so the limit applies to all of them together; raise
maxin the middleware config if that is too tight for your team. - Auto-created admins have no password. Password login for existing admins stays available; disabling it requires Strapi's paid SSO feature.
- The admin panel must be served from the same origin as the API (Strapi default).
- Check
FIREBASE_JSON_ENCRYPTION_KEYis set (minimum 32 characters) - Upload Firebase service account JSON via admin panel
- Restart Strapi after uploading config
- Check console for initialization errors
- Token expired (1 hour TTL) - get a fresh token from client
- Wrong Firebase project - ensure service account matches your app
- Check Firebase Console for service status
Install and configure Strapi email provider:
yarn add @strapi/provider-email-sendgrid// config/plugins.js
module.exports = () => ({
email: {
config: {
provider: "sendgrid",
providerOptions: { apiKey: process.env.SENDGRID_API_KEY },
settings: { defaultFrom: "noreply@yourapp.com" },
},
},
// ... firebase-authentication config
});MIT License - see LICENSE.md