Integrating Firebase Authentication with Devise Fallback in PropertyWebBuilder

PropertyWebBuilder allows you to switch between Firebase Authentication and Devise with a single environment variable, automatically routing users to the correct login UI without changing any application code.

This guide explains how to implement and toggle between Firebase and Devise authentication in the PropertyWebBuilder open-source Rails application. The architecture relies on a provider-agnostic configuration layer that delegates routing decisions at runtime based on the AUTH_PROVIDER environment variable.

Selecting the Authentication Provider

The Pwb::AuthConfig module in config/initializers/pwb_auth.rb acts as the single source of truth for determining which authentication system is active.


# config/initializers/pwb_auth.rb

module Pwb
  module AuthConfig
    VALID_PROVIDERS = %i[firebase devise].freeze

    class << self
      def provider
        @provider ||= ENV.fetch('AUTH_PROVIDER', 'firebase').to_sym
      end

      def firebase?
        provider == :firebase
      end

      def devise?
        provider == :devise
      end
    end
  end
end

To switch providers, set the environment variable and restart the server:


# Use Firebase (default)

export AUTH_PROVIDER=firebase

# Use Devise fallback

export AUTH_PROVIDER=devise

The initializer validates the configuration at boot time and logs the active provider to the Rails log.

Firebase Login Flow Implementation

When AUTH_PROVIDER is set to firebase, PropertyWebBuilder serves its own Tailwind-styled authentication UI through dedicated routes and controllers.

Firebase Routes

The Firebase-specific endpoints are defined in config/routes.rb:


# config/routes.rb

get "/pwb_login"            => "firebase_login#index"
get "/pwb_sign_up"          => "firebase_login#sign_up"
get "/pwb_forgot_password"  => "firebase_login#forgot_password"
get "/pwb_change_password"  => "firebase_login#change_password"

Firebase Controller Logic

The Pwb::FirebaseLoginController in app/controllers/pwb/firebase_login_controller.rb handles these routes with two critical before_action filters:


# app/controllers/pwb/firebase_login_controller.rb

before_action :redirect_if_devise_auth
before_action :redirect_if_signed_in, except: [:change_password]

The redirect_if_devise_auth method ensures that if the provider is accidentally switched to Devise, users are redirected to the appropriate Devise path instead of seeing the Firebase UI.

Token Verification and User Creation

When a user submits credentials via the Firebase UI, the client sends an ID token to the /auth/firebase endpoint. The Pwb::FirebaseAuthService validates this token using Pwb::FirebaseTokenVerifier:


# app/services/pwb/firebase_auth_service.rb

verifier = FirebaseTokenVerifier.new(@token)
payload  = verifier.verify!

user = Pwb::User.find_by(firebase_uid: payload['sub'])

# Create or update user, assign roles, and sign in

The verifier handles certificate rotation, expiration checks, and issuer validation against Google's Firebase certificates.

Devise Fallback and Automatic Redirection

When AUTH_PROVIDER is set to devise, PropertyWebBuilder delegates authentication to standard Devise controllers while ensuring Firebase routes remain inaccessible.

AuthProviderRedirect Concern

The AuthProviderRedirect concern in app/controllers/concerns/auth_provider_redirect.rb is included in all Devise controllers (e.g., app/controllers/pwb/devise/sessions_controller.rb):


# app/controllers/concerns/auth_provider_redirect.rb

def redirect_if_firebase_auth
  return if Pwb::AuthConfig.devise?
  
  firebase_path = firebase_equivalent_path
  redirect_to firebase_path, notice: "Please use the Firebase login."
end

Path Mapping Logic

The concern maps Devise controller actions to their Firebase equivalents:


# app/controllers/concerns/auth_provider_redirect.rb

base_path = case controller_name
            when 'sessions'      then '/pwb_login'
            when 'registrations' 
              action_name == 'edit' ? '/pwb_change_password' : '/pwb_sign_up'
            when 'passwords'     then '/pwb_forgot_password'
            else '/pwb_login'
            end

This ensures that if a user bookmarks /users/sign_in while Firebase is active, they are automatically redirected to /pwb_login without error.

Helper Methods and View Integration

The AuthHelper module in app/helpers/auth_helper.rb provides unified path helpers that abstract the provider selection:


# app/helpers/auth_helper.rb

def login_path(locale: nil)
  Pwb::AuthConfig.login_path(locale: locale)
end

def signup_path(locale: nil)
  Pwb::AuthConfig.signup_path(locale: locale)
end

Views use these helpers to generate links that automatically point to the correct authentication endpoint:

<%# app/views/layouts/_header.html.erb %>

<% if user_signed_in? %>
  <%= link_to "Logout", Pwb::AuthConfig.logout_path %>
<% else %>
  <%= link_to "Login", login_path %>
  <%= link_to "Sign up", signup_path %>
<% end %>

When AUTH_PROVIDER is firebase, these resolve to /pwb_login and /pwb_sign_up. When set to devise, they resolve to the localized Devise routes (e.g., /en/users/sign_in).

Switching Between Providers at Runtime

To change authentication methods without deploying code:

  1. Update the environment variable:

    export AUTH_PROVIDER=devise
    # or
    
    export AUTH_PROVIDER=firebase
  2. Restart the Rails server to reload the initializer.

  3. Verify the switch in the logs:

    
    [Pwb::AuthConfig] Using devise authentication
    

The application handles all routing and UI changes automatically. No database migrations or view modifications are required.

Summary

  • Runtime Configuration: Set AUTH_PROVIDER to firebase or devise in config/initializers/pwb_auth.rb to switch authentication systems without code changes.
  • Firebase Implementation: Uses Pwb::FirebaseLoginController for UI and Pwb::FirebaseAuthService with Pwb::FirebaseTokenVerifier for token validation.
  • Devise Fallback: Standard Devise controllers include AuthProviderRedirect to ensure Firebase routes redirect appropriately when Devise is active.
  • Unified Interface: AuthHelper methods like login_path abstract provider differences, allowing views to remain provider-agnostic.

Frequently Asked Questions

How do I switch from Firebase to Devise authentication?

Set the AUTH_PROVIDER environment variable to devise and restart your Rails server. The application will automatically redirect Firebase routes to their Devise equivalents and display standard Devise views instead of the Firebase UI.

What happens if a user visits a Devise URL while Firebase is active?

The AuthProviderRedirect concern intercepts the request and redirects the user to the corresponding Firebase path. For example, visiting /users/sign_in redirects to /pwb_login, ensuring users always see the correct authentication interface for the active provider.

How does PropertyWebBuilder verify Firebase ID tokens?

The Pwb::FirebaseTokenVerifier service validates tokens against Google's public certificates, checking issuer, audience, and expiration claims. The Pwb::FirebaseAuthService then uses the verified payload to find or create a user record based on the firebase_uid stored in the database.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →