• Skip to secondary menu
  • Skip to main content
  • Skip to primary sidebar
  • Home
  • Projects
  • Products
  • Themes
  • Tools
  • Request for Quote

Vengala Vinay

Having 12+ Years of Experience in Software Development

  • Home
  • WordPress
  • PHP
    • Codeigniter
  • Django
  • Magento
  • Selenium
  • Server
Home » WordPress Development Recipe: Secure token-based API authentication for Firebase Realtime DB in custom plugins

WordPress Development Recipe: Secure token-based API authentication for Firebase Realtime DB in custom plugins

Firebase Realtime Database: Securing Custom WordPress API Endpoints with Token-Based Authentication

When integrating custom WordPress plugins with external services like Firebase Realtime Database (RTDB), robust authentication is paramount. This recipe details a secure, token-based approach for authenticating API requests from your WordPress backend to Firebase RTDB, ensuring data integrity and access control. We’ll leverage WordPress’s built-in REST API and Firebase’s Admin SDK for a seamless integration.

Prerequisites and Setup

Before we begin, ensure you have the following:

  • A Firebase project with Realtime Database enabled.
  • A Firebase Service Account key (JSON file) with appropriate permissions for your RTDB. Download this from your Firebase project settings under “Service accounts”.
  • Composer installed for managing PHP dependencies.
  • A WordPress installation where you’ll develop your custom plugin.

Installing the Firebase Admin SDK for PHP

The Firebase Admin SDK simplifies interaction with Firebase services. We’ll install it using Composer within your plugin’s directory.

Navigate to your plugin’s root directory in your terminal and run:

composer require firebase/php-admin-sdk

Storing Service Account Credentials Securely

Never commit your Firebase Service Account JSON file directly into your plugin’s repository. A more secure approach is to store it outside the web-accessible directory and reference it via an environment variable or a secure configuration file. For this example, we’ll assume you’ve placed the JSON file in a secure location and are referencing its path.

In your plugin’s main file (e.g., my-firebase-plugin.php), define a constant for the path to your service account credentials. This should be done early in your plugin’s lifecycle.

// my-firebase-plugin.php

// Define a secure path to your Firebase service account credentials.
// It's highly recommended to store this outside your web root.
// For demonstration, we'll use a placeholder. In production, use environment variables
// or a secure configuration management system.
define( 'FIREBASE_SERVICE_ACCOUNT_PATH', '/path/to/your/secure/firebase-credentials.json' );

// Ensure Composer's autoloader is included
require_once plugin_dir_path( __FILE__ ) . 'vendor/autoload.php';

// ... rest of your plugin code

Initializing the Firebase Admin SDK

Initialize the Firebase Admin SDK once when your plugin loads. This involves creating a Firebase app instance using your service account credentials.

use Kreait\Firebase\Factory;
use Kreait\Firebase\ServiceAccount;

/**
 * Initializes the Firebase Admin SDK.
 */
function initialize_firebase_app() {
    if ( ! defined( 'FIREBASE_SERVICE_ACCOUNT_PATH' ) || ! file_exists( FIREBASE_SERVICE_ACCOUNT_PATH ) ) {
        // Log an error or handle this critical misconfiguration
        error_log( 'Firebase Service Account path is not defined or file does not exist.' );
        return false;
    }

    try {
        $serviceAccount = ServiceAccount::fromJsonFile( FIREBASE_SERVICE_ACCOUNT_PATH );
        $firebase = ( new Factory() )
            ->withServiceAccount( $serviceAccount )
            // Replace with your Firebase project ID
            ->withProjectId( 'your-firebase-project-id' )
            ->create();

        // Store the Firebase app instance in a global variable or a WordPress option
        // for easy access across different parts of your plugin.
        // Using a global is simpler for this example, but consider a more robust
        // approach for complex plugins.
        $GLOBALS['firebase_app'] = $firebase;

        return $firebase;

    } catch ( \Exception $e ) {
        error_log( 'Firebase initialization failed: ' . $e->getMessage() );
        return false;
    }
}

// Hook into an early action to ensure Firebase is initialized before it's needed.
// 'plugins_loaded' is a good candidate, or a custom hook.
add_action( 'plugins_loaded', 'initialize_firebase_app' );

/**
 * Get the Firebase app instance.
 *
 * @return \Kreait\Firebase\FirebaseApp|false The Firebase app instance or false on failure.
 */
function get_firebase_app() {
    if ( isset( $GLOBALS['firebase_app'] ) && $GLOBALS['firebase_app'] instanceof \Kreait\Firebase\FirebaseApp ) {
        return $GLOBALS['firebase_app'];
    }
    // Attempt to initialize if not already done (e.g., if hook didn't run yet or failed)
    return initialize_firebase_app();
}

Creating a Secure WordPress REST API Endpoint

We’ll create a custom WordPress REST API endpoint that will act as a proxy to our Firebase RTDB. This endpoint will receive a secure token from the client (or another authenticated source) and use it to authenticate with Firebase.

/**
 * Registers a custom REST API endpoint for Firebase RTDB interaction.
 */
function register_firebase_rtdb_endpoint() {
    register_rest_route( 'myplugin/v1', '/data/(?P<key>[\w-]+)', array(
        'methods' => WP_REST_Server::CREATABLE, // Or WP_REST_Server::READABLE for GET
        'callback' => 'handle_firebase_rtdb_request',
        'permission_callback' => '__return_true', // We'll handle auth within the callback
        'args' => array(
            'key' => array(
                'required' => true,
                'validate_callback' => function( $param, $request, $key ) {
                    return is_string( $param ) && ! empty( $param );
                }
            ),
            'data' => array(
                'required' => false, // For POST/PUT requests
                'validate_callback' => function( $param, $request, $key ) {
                    // Basic validation: ensure it's a JSON string or an array
                    if ( is_string( $param ) ) {
                        json_decode( $param );
                        return ( json_last_error() === JSON_ERROR_NONE );
                    } elseif ( is_array( $param ) ) {
                        return true;
                    }
                    return false;
                }
            ),
            'firebase_token' => array(
                'required' => true,
                'validate_callback' => function( $param, $request, $key ) {
                    return is_string( $param ) && ! empty( $param );
                }
            ),
        ),
    ) );
}
add_action( 'rest_api_init', 'register_firebase_rtdb_endpoint' );

/**
 * Handles requests to the Firebase RTDB endpoint.
 *
 * @param WP_REST_Request $request Full data.
 * @return WP_REST_Response Response object.
 */
function handle_firebase_rtdb_request( WP_REST_Request $request ) {
    $firebase_token = $request->get_param( 'firebase_token' );
    $key = $request->get_param( 'key' );
    $data = $request->get_param( 'data' ); // For POST/PUT

    // 1. Validate the Firebase Token
    // This is a crucial step. The token passed here should be a Firebase ID Token
    // obtained from a logged-in Firebase user or a custom token generated by your backend.
    // For simplicity, we'll assume it's a Firebase ID Token.
    // In a real-world scenario, you'd verify this token's authenticity.
    // The Firebase Admin SDK can verify ID tokens.

    $firebase_app = get_firebase_app();
    if ( ! $firebase_app ) {
        return new WP_REST_Response( array( 'message' => 'Firebase service not available.' ), 503 ); // Service Unavailable
    }

    try {
        // Verify the ID token while checking if the token is revoked.
        // This requires the Firebase Auth SDK.
        // If you're using custom tokens, the verification logic would differ.
        // For this example, we'll simulate verification.
        // In a production environment, you MUST verify the token.

        // Example using Firebase Auth (requires 'firebase/php-jwt' and 'google/auth' dependencies)
        // $auth = $firebase_app->getAuth();
        // $verifiedIdToken = $auth->verifyIdToken( $firebase_token );
        // $uid = $verifiedIdToken->claims()->get('uid');

        // --- SIMULATED TOKEN VERIFICATION FOR DEMONSTRATION ---
        // In a real app, replace this with actual token verification.
        // This simulation assumes any non-empty token is valid for brevity.
        if ( empty( $firebase_token ) || strlen( $firebase_token ) < 10 ) { // Basic check
             throw new \Exception( 'Invalid Firebase token.' );
        }
        // --- END SIMULATION ---

    } catch ( \Exception $e ) {
        error_log( 'Firebase token verification failed: ' . $e->getMessage() );
        return new WP_REST_Response( array( 'message' => 'Authentication failed.' ), 401 ); // Unauthorized
    }

    // 2. Interact with Firebase RTDB
    $database = $firebase_app->getDatabase();
    $ref = $database->getReference( 'your_firebase_path/' . $key ); // e.g., 'users/user_id/settings/key'

    // Determine the HTTP method and perform the corresponding action
    $method = $request->get_method();

    if ( $method === 'POST' || $method === 'PUT' ) {
        // Ensure data is properly decoded if it was sent as a JSON string
        if ( is_string( $data ) ) {
            $decoded_data = json_decode( $data, true );
            if ( json_last_error() !== JSON_ERROR_NONE ) {
                return new WP_REST_Response( array( 'message' => 'Invalid JSON data provided.' ), 400 ); // Bad Request
            }
            $data = $decoded_data;
        }

        if ( ! is_array( $data ) ) {
             return new WP_REST_Response( array( 'message' => 'Data must be an array or valid JSON string.' ), 400 );
        }

        try {
            // Use set() for PUT (overwrite) or push() for POST (add new child with unique key)
            // For this example, we'll use set() to update/create the specific key.
            // If you need to add unique children, you'd use $ref->push($data)->getKey();
            $ref->set( $data );
            return new WP_REST_Response( array( 'message' => 'Data successfully saved to Firebase.', 'key' => $key ), 200 );
        } catch ( \Exception $e ) {
            error_log( 'Firebase RTDB set operation failed: ' . $e->getMessage() );
            return new WP_REST_Response( array( 'message' => 'Failed to save data to Firebase.' ), 500 ); // Internal Server Error
        }
    } elseif ( $method === 'GET' ) {
        try {
            $snapshot = $ref->getSnapshot();
            if ( $snapshot->exists() ) {
                return new WP_REST_Response( $snapshot->getValue(), 200 );
            } else {
                return new WP_REST_Response( array( 'message' => 'Data not found.' ), 404 ); // Not Found
            }
        } catch ( \Exception $e ) {
            error_log( 'Firebase RTDB get operation failed: ' . $e->getMessage() );
            return new WP_REST_Response( array( 'message' => 'Failed to retrieve data from Firebase.' ), 500 );
        }
    } elseif ( $method === 'DELETE' ) {
        try {
            $ref->remove();
            return new WP_REST_Response( array( 'message' => 'Data successfully deleted from Firebase.', 'key' => $key ), 200 );
        } catch ( \Exception $e ) {
            error_log( 'Firebase RTDB remove operation failed: ' . $e->getMessage() );
            return new WP_REST_Response( array( 'message' => 'Failed to delete data from Firebase.' ), 500 );
        }
    }

    // Handle unsupported methods
    return new WP_REST_Response( array( 'message' => 'Method not allowed.' ), 405 ); // Method Not Allowed
}

Token Generation and Verification Strategy

The security of this system hinges on how you generate and verify the firebase_token. Here are common strategies:

  • Firebase ID Tokens: If your frontend application uses Firebase Authentication, it can obtain an ID Token upon user login. This token is then passed to your WordPress API endpoint. Your WordPress backend, using the Firebase Admin SDK’s Auth module, verifies this ID Token. This is the most robust method for user-specific data access.
  • Custom Tokens: Your WordPress backend can generate custom tokens using the Firebase Admin SDK. These tokens can be signed with your service account credentials and can contain custom claims. The frontend then exchanges this custom token for an ID token or uses it directly if your Firebase security rules allow. This is useful for server-to-server communication or when you need to grant temporary access without a full Firebase Auth user.
  • Short-Lived API Keys (Less Recommended for Firebase RTDB): For simpler scenarios, you might generate unique, short-lived API keys within WordPress and pass them. However, this doesn’t directly leverage Firebase’s robust authentication mechanisms and requires you to implement custom security rules in Firebase based on these keys, which is more complex and less secure than using Firebase’s native tokens.

Crucially, the example code above includes a placeholder for token verification. You MUST implement actual token verification using the Firebase Admin SDK’s Auth component to prevent unauthorized access.

// Example of actual Firebase ID Token verification in handle_firebase_rtdb_request:

// ... inside handle_firebase_rtdb_request function ...

$firebase_app = get_firebase_app();
if ( ! $firebase_app ) {
    return new WP_REST_Response( array( 'message' => 'Firebase service not available.' ), 503 );
}

try {
    $auth = $firebase_app->getAuth();
    // Verify the ID token while checking if the token is revoked.
    $verifiedIdToken = $auth->verifyIdToken( $firebase_token );
    $uid = $verifiedIdToken->claims()->get('uid'); // Get the user ID from the token

    // You can also check custom claims if you've set them
    // $custom_claim_value = $verifiedIdToken->claims()->get('your_custom_claim');

    // Use the $uid to scope Firebase RTDB operations, e.g.,
    // $ref = $database->getReference( 'users/' . $uid . '/data/' . $key );

} catch ( \Exception $e ) {
    error_log( 'Firebase token verification failed: ' . $e->getMessage() );
    return new WP_REST_Response( array( 'message' => 'Authentication failed.' ), 401 );
}

// ... rest of your RTDB interaction logic using $uid if needed ...

Firebase Realtime Database Security Rules

Your Firebase RTDB security rules are the final layer of defense. They dictate who can read and write data. When using token-based authentication, your rules should leverage the authenticated user’s UID (available in the token) to enforce access control.

{
  "rules": {
    "users": {
      "$uid": {
        // Allow users to read and write their own data
        ".read": "auth != null && auth.uid == $uid",
        ".write": "auth != null && auth.uid == $uid",
        "settings": {
          // Example: Allow writing to specific settings if the user is authenticated
          // and the key matches a pattern or is allowed.
          "$key": {
            ".validate": "newData.hasChildren(['some_field'])", // Example validation
            "some_field": {
              ".validate": "newData.isString() && newData.val().length < 100"
            }
          }
        }
      }
    },
    "public_data": {
      // Allow anyone to read public data
      ".read": true,
      // Only allow authenticated users to write to public data (or specific conditions)
      ".write": "auth != null"
    }
  }
}

In the example above, auth != null checks if a user is authenticated, and auth.uid == $uid ensures they are accessing data belonging to their own user ID. Adjust these rules based on your application’s specific requirements.

Client-Side Implementation (Conceptual)

On the client-side (e.g., a JavaScript application or a theme using AJAX), you would:

  • Authenticate the user with Firebase Authentication.
  • Obtain the user’s ID Token using firebase.auth().currentUser.getIdToken().
  • Make an AJAX request to your WordPress REST API endpoint (e.g., /wp-json/myplugin/v1/data/my_key), including the ID Token in the request headers or as a parameter.
// Conceptual JavaScript example using fetch API

async function saveDataToFirebaseViaWP(key, data) {
    const user = firebase.auth().currentUser;
    if (!user) {
        console.error("User not logged in.");
        return;
    }

    try {
        const idToken = await user.getIdToken();
        const wpApiUrl = '/wp-json/myplugin/v1/data/' + encodeURIComponent(key);

        const response = await fetch(wpApiUrl, {
            method: 'POST', // or 'GET', 'DELETE'
            headers: {
                'Content-Type': 'application/json',
                // You might pass the token in a header like 'Authorization: Bearer YOUR_ID_TOKEN'
                // or as a parameter as done in the PHP example.
                // For this example, we'll pass it as a parameter as per the PHP callback.
            },
            body: JSON.stringify({
                firebase_token: idToken,
                data: data // The data to save
            })
        });

        if (!response.ok) {
            const errorData = await response.json();
            throw new Error(`HTTP error! status: ${response.status}, message: ${errorData.message}`);
        }

        const result = await response.json();
        console.log('Success:', result);
        return result;

    } catch (error) {
        console.error('Error saving data:', error);
    }
}

// Example usage:
// saveDataToFirebaseViaWP('user_settings_123', { theme: 'dark', notifications: true });

Conclusion

This recipe provides a robust framework for securing your WordPress plugin’s interactions with Firebase Realtime Database. By implementing token-based authentication, verifying tokens rigorously on the server-side, and leveraging Firebase’s security rules, you can ensure data privacy and integrity. Remember to adapt the token verification logic and Firebase security rules to precisely match your application’s security posture.

Primary Sidebar

A little about the Author

Having 12+ Years of Experience in Software Development, Vinay is a principal software architect, senior systems engineer, and elite technical consultant. He specializes in bespoke PHP/WordPress development, high-performance Magento 2 & Shopify architectures, custom plugin/theme development from scratch, and legacy code modernization (including VB6, VB.NET, PyQt, and Crystal Reports). Known for solving complex database bottlenecks, speed optimization (Core Web Vitals), and advanced security code auditing, Vinay engineers production-ready systems designed to scale under heavy concurrent load conditions.



Chat on WhatsApp

Recent Posts

  • Reducing database query bloat in Sage Roots modern environments layouts using custom lazy loaders
  • Performance Optimization: Tuning PHP-FPM and opcache pools for high-concurrency Firebase Realtime DB handlers
  • Reducing Largest Contentful Paint (LCP) by optimizing custom script enqueuing structures in legacy plugins
  • How to implement native Redis caching layers for high-volume custom taxonomy queries in Carbon Fields custom wrappers
  • Building secure B2B pricing grids with custom REST API Controllers endpoints and role overrides

Categories

  • apache (1)
  • Business & Monetization (390)
  • Centos (4)
  • Comparisons & Decision Making (55)
  • Debian (2)
  • Debugging & Troubleshooting (658)
  • Desktop Applications (14)
  • DevOps (7)
  • DevOps & Cloud Scaling (962)
  • Django (1)
  • Laravel (4)
  • Migration & Architecture (192)
  • Mobile Applications (24)
  • MySQL (1)
  • Performance & Optimization (872)
  • PHP (5)
  • PHP Development (48)
  • Plugins & Themes (244)
  • Programming Languages (9)
  • Python (20)
  • Ruby on Rails (1)
  • Security & Compliance (639)
  • SEO & Growth (492)
  • Server (23)
  • Ubuntu (9)
  • VB6 & VB.NET (8)
  • Web Applications & Frontend (19)
  • Web Assembly (Wasm) (2)
  • WordPress (22)
  • WordPress Plugin Development (182)
  • WordPress Plugin Development (197)
  • WordPress Plugin Development (330)
  • WordPress Theme Development (357)

Recent Posts

  • Reducing database query bloat in Sage Roots modern environments layouts using custom lazy loaders
  • Performance Optimization: Tuning PHP-FPM and opcache pools for high-concurrency Firebase Realtime DB handlers
  • Reducing Largest Contentful Paint (LCP) by optimizing custom script enqueuing structures in legacy plugins

Top Categories

  • DevOps & Cloud Scaling (962)
  • Performance & Optimization (872)
  • Debugging & Troubleshooting (658)
  • Security & Compliance (639)
  • SEO & Growth (492)
  • Business & Monetization (390)

Our Products

  • ERP & LMS Systems (4)
  • Directories & Marketplaces (4)
  • Healthcare Portals (3)
  • Point of Sale (POS) (2)
  • E-Commerce Engines (2)

Our Services

  • E-Commerce Development (10)
  • WordPress Development (8)
  • Python & Desktop GUI (7)
  • General Consulting (7)
  • Legacy Modernization (5)
  • Mobile App Development (4)

Copyright © 2026 · Vinay Vengala