@grace-studio/firebase-server
v0.0.1-beta.0
Published
Server-side Firebase utilities for Firebase Functions
Keywords
Readme
@grace-studio/firebase-server
Server-side Firebase utilities for Firebase Functions.
Installation
npm install @grace-studio/firebase-serverModules
This package provides server-side utilities for Firebase Functions.
For client-side React utilities, see @grace-studio/firebase-react (coming soon).
OTP Module
The OTP module provides one-time password functionality with email delivery for Firebase functions.
Basic Usage
import { onCall } from "firebase-functions/https";
import { onSchedule } from "firebase-functions/scheduler";
import { getApp } from "firebase-admin/app";
import {
otp,
OTPConfigCommon,
OTPConfigInitialize,
} from "@grace-studio/firebase-server";
// Get your Firebase Admin app instance
const app = getApp();
// Shared configuration used by both endpoints
const sharedConfig: OTPConfigCommon = {
app, // Firebase Admin app instance
firestoreCollectionPath: "otp_codes", // Firestore collection to store OTP data
};
// Optional: Configure logging level for debugging
// Options: "verbose", "regular"
otp.configureLogger("verbose");
/**
* Endpoint 1: Initialize OTP Sign-in
*
* This endpoint generates a new OTP code and sends it via email.
* Call this when a user wants to sign in with their email.
*
* Expected request data: { email: string }
* Returns: { newUser: boolean, otpTTL: number, expiresAt: Timestamp }
*/
export const initializeOTPSignIn = onCall({}, async (req) => {
const { email } = req.data;
const config: OTPConfigInitialize = {
...sharedConfig,
// Security settings
saltRounds: 6, // bcrypt salt rounds for hashing OTP
maxSignInAttempts: 3, // Max failed validation attempts before blocking
// OTP settings
otpLength: 8, // Length of the generated OTP code (default: 8)
otpTTL: 600, // Time-to-live in seconds (10 minutes)
// Optional: Custom OTP generator function
// customOtpGenerator: (length) => nanoid(),
// Email configuration
nodeMailerConfig: {
smtp: {
host: "smtp.ethereal.email", // Your SMTP server
port: 587, // SMTP port (587 for TLS, 465 for SSL)
auth: {
user: "[email protected]", // SMTP username
pass: "your-password", // SMTP password
},
},
email: {
from: '"Your App Name" <[email protected]>', // Sender info
// Email templates with template variables
// Available variables: {otp} and {email}
subjectTemplate: "One time password for Your App - {otp}",
// HTML email body (supports HTML tags)
htmlTemplate: `
<h2>Welcome to Your App!</h2>
<p>Hi {email}!</p>
<p>Your one-time password is: <strong style="font-size: 24px; color: #007bff;">{otp}</strong></p>
<p>This code will expire in 10 minutes.</p>
<p>If you didn't request this, please ignore this email.</p>
`,
// Plain text email body (fallback for email clients that don't support HTML)
textTemplate: `
Welcome to Your App!
Hi {email}!
Your one-time password is: {otp}
This code will expire in 10 minutes.
If you didn't request this, please ignore this email.
`,
},
},
};
// Generate OTP and send email
return otp.initialize(config)(email);
});
/**
* Endpoint 2: Validate OTP
*
* This endpoint validates the OTP code entered by the user.
* Call this when the user submits their OTP code.
*
* Expected request data: { email: string, otp: string }
* Returns: { customToken: string }
* Throws: HttpsError for validation failures
*/
export const validateOTP = onCall({}, async (req) => {
const { email, otp: userOtp } = req.data;
// Validate the OTP code
// This will check if the code is correct, not expired, and hasn't exceeded max attempts
return otp.validate(sharedConfig)(email, userOtp);
});
/**
* Endpoint 3: Periodic Cleanup (Optional)
*
* This endpoint cleans up expired OTP documents from Firestore.
* Use this as a scheduled function (cron job) to maintain database hygiene.
*
* Expected request data: none
* Returns: { deletedCount: number }
*/
export const cleanupExpiredOTPs = onSchedule("every 24 hours", async () => {
// Clean up expired OTP documents every 24 hours
return otp.periodicCleanup(sharedConfig)();
});
// Alternative: HTTP callable cleanup endpoint for manual/custom scheduling
export const cleanupExpiredOTPsManual = onCall({}, async () => {
return otp.periodicCleanup(sharedConfig)();
});Endpoint Flow
User enters email → Call
initializeOTPSignIn- Generates a random OTP code (default 8 characters)
- Creates user if they don't exist
- Stores OTP hash securely in Firestore with expiration
- Sends email with the OTP code
- Returns:
{ newUser: boolean, otpTTL: number, expiresAt: Timestamp }
User enters OTP code → Call
validateOTP- Validates the OTP against stored hash
- Checks expiration and attempt limits
- Sets user's emailVerified to true on success
- Generates Firebase custom token for authentication
- Returns:
{ customToken: string } - Throws
HttpsErroron validation failures (expired, invalid, max attempts)
Scheduled cleanup →
cleanupExpiredOTPs(runs automatically)- Queries for all expired OTP documents in Firestore
- Batch deletes expired documents
- Returns:
{ deletedCount: number } - Recommended: Run every 6-24 hours to maintain database hygiene
Template Variables in Email
Email templates support dynamic content using template variables:
{otp}- The generated OTP code (e.g., "123456"){email}- The recipient's email address (e.g., "[email protected]")
Example:
subjectTemplate: "Your {otp} code for MyApp";
// Becomes: "Your 123456 code for MyApp"
htmlTemplate: "Hi {email}, your code is <b>{otp}</b>";
// Becomes: "Hi [email protected], your code is <b>123456</b>"Template Tips:
- Use
{otp}in the subject line for easy identification - Include
{email}for personalization - Provide both HTML and text templates for better compatibility
- Keep templates clear and include expiration information
Configuration Options
OTPConfigCommon
app: Firebase Admin App instancefirestoreCollectionPath: Firestore collection path for storing OTP data
OTPConfigInitialize (extends OTPConfigCommon)
saltRounds: Number of salt rounds for bcrypt hashingmaxSignInAttempts: Maximum number of sign-in attempts allowedotpLength: Length of the generated OTP codeotpTTL: Time-to-live for OTP in secondscustomOtpGenerator: Optional custom OTP generator functionnodeMailerConfig: Email configuration object
NodeMailer Configuration
nodeMailerConfig: {
smtp: {
host: "your-smtp-host",
port: 587,
auth: {
user: "your-username",
pass: "your-password"
}
},
email: {
from: '"Sender Name" <[email protected]>',
subjectTemplate: "Your OTP is {otp}",
htmlTemplate: "Your OTP: <b>{otp}</b>",
textTemplate: "Your OTP: {otp}"
}
}Template Variables
Email templates support the following variables:
{otp}: The generated OTP code{email}: The recipient's email address
Methods
otp.initialize(config)- Initializes OTP generation and sends emailotp.validate(config)- Validates an OTP codeotp.configureLogger(level)- Sets logging level ("verbose", "info", "warn", "error")otp.periodicCleanup(config)- Cleans up expired OTP records
Import Options
// Default import
import { otp } from "@grace-studio/firebase-server";
// Type imports
import {
OTPConfigCommon,
OTPConfigInitialize,
LogLevel,
} from "@grace-studio/firebase-server";For React utilities, install the separate package:
npm install @grace-studio/firebase-react # Coming soonDevelopment
# Install dependencies
npm install
# Build the package
npm run build
# Clean build artifacts
npm run cleanPublishing
# Version and publish beta
npm run version:beta
npm run publish:betaLicense
ISC
