Build Secure Shopify Apps with App Bridge

Senior Software Engineer with 12 years of expertise in Ruby on Rails and Vue.js, specializing in health, e-commerce, staffing, and transport. Experienced in software development and version analysis.
Search for a command to run...

Senior Software Engineer with 12 years of expertise in Ruby on Rails and Vue.js, specializing in health, e-commerce, staffing, and transport. Experienced in software development and version analysis.
No comments yet. Be the first to comment.
Motivation After building several Shopify embedded apps, I've learned valuable lessons about what works (and what definitely doesn't) in the embedded app environment. Today, I'm sharing these insights to help you avoid common pitfalls and build bette...

As developers, we're always looking for ways to streamline our deployment process while maintaining security and reliability. Today, I'm excited to share my experience setting up an automated deployment pipeline for a Rails application using Dokku an...

The Challenge: Modernizing Rails Deployment When I recently needed to deploy my Rails 8 application with multiple databases, I faced a common dilemma: choosing between expensive managed solutions and complex self-managed servers. My requirements were...

The Cost-Benefit Realization As a Rails developer who recently migrated from Heroku to Dokku, I want to share my journey and the surprising benefits I discovered. This transition wasn't just about cost savings—it opened up new possibilities for my de...

As a developer working with Shopify's ecosystem, I recently built a multi-tenant SaaS application that synchronizes customer data between Shopify stores and external services. In this article, I'll share my experience and technical insights into creating a secure, scalable Shopify app using App Bridge.
Our application needed to:
Let's dive into how we accomplished these requirements using Rails 8 and Shopify's App Bridge.
First, we set up our Rails application with the necessary Shopify integrations. Here's how our initial configuration looked:
ShopifyApp.configure do |config|
config.embedded_app = true
config.scope = "read_customers,write_customers"
config.after_authenticate_job = false
config.api_version = "2024-10"
config.shop_session_repository = "Shop"
config.webhooks = [
{ topic: "app/uninstalled", address: "webhooks/app_uninstalled" },
{ topic: "customers/create", address: "webhooks/customers_create" },
{ topic: "customers/update", address: "webhooks/customers_update" }
]
end
Our core data model revolves around the Shop model, which handles multi-tenancy:
class Shop < ActiveRecord::Base
include ShopifyApp::ShopSessionStorageWithScopes
has_many :customers, dependent: :destroy
encrypts :api_key, deterministic: true
end
One of the key aspects was creating a seamless embedded experience. We achieved this through our layout configuration:
<%# app/views/layouts/embedded_app.html.erb %>
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://unpkg.com/@shopify/app-bridge@3.7.9"></script>
<script>
var AppBridge = window['app-bridge'];
var createApp = AppBridge.default;
var app = createApp({
apiKey: "<%= ShopifyApp.configuration.api_key %>",
host: "<%= @host %>",
forceRedirect: true
});
</script>
</head>
<body>
<%= yield %>
</body>
</html>
We implemented authenticated controllers to ensure secure access:
class AuthenticatedController < ApplicationController
include ShopifyApp::EnsureHasSession
before_action :ensure_store_settings
private
def ensure_store_settings
redirect_to settings_path unless current_shop.setup_completed?
end
end
Handling webhooks securely was crucial for our app. Here's our webhook processing implementation:
class WebhooksController < ApplicationController
include ShopifyApp::WebhookVerification
def customers_create
shop = Shop.find_by(shopify_domain: params[:shop_domain])
if shop
shop.with_shopify_session do
process_customer_data(params)
end
end
head :ok
end
private
def process_customer_data(data)
CustomerProcessingJob.perform_later(
shop_id: shop.id,
customer_data: data
)
end
end
We used Solid Queue for reliable background processing:
class CustomerProcessingJob < ApplicationJob
def perform(shop_id:, customer_data:)
shop = Shop.find(shop_id)
shop.with_shopify_session do
customer = shop.customers.find_or_initialize_by(
shopify_customer_id: customer_data["id"]
)
customer.update!(
email: customer_data["email"],
first_name: customer_data["first_name"],
last_name: customer_data["last_name"]
)
end
end
end
We implemented Shopify's billing API to handle subscriptions:
config.billing = ShopifyApp::BillingConfiguration.new(
charge_name: "App Subscription",
amount: 4.99,
interval: ShopifyApp::BillingConfiguration::INTERVAL_EVERY_30_DAYS,
trial_days: 7
)
We created a clean, responsive interface using Tailwind CSS:
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8 pb-12 pt-20">
<div class="sm:flex sm:items-center">
<div class="sm:flex-auto">
<h1 class="text-base font-semibold leading-6 text-gray-900">
Customers
</h1>
<p class="mt-2 text-sm text-gray-700">
Manage your synchronized customers
</p>
</div>
</div>
<%= render "customer_list", customers: @customers %>
</div>
Throughout this project, I learned several valuable lessons:
Session Management: Always use Shopify's session tokens for authentication rather than storing raw access tokens.
Webhook Reliability: Implement idempotency in webhook processing to handle potential duplicate events.
Background Jobs: Use background jobs for any operations that might take more than a few seconds to complete.
Error Handling: Implement comprehensive error handling and logging, especially for webhook processing and API calls.
Security: Always encrypt sensitive data and never expose API keys in the frontend.
Building a multi-tenant Shopify app requires careful consideration of security, scalability, and user experience. By leveraging Rails, App Bridge, and modern development practices, we created a robust application that securely handles multiple stores and their data.
The combination of Shopify's App Bridge, Rails 8, and modern tools like Solid Queue and Tailwind CSS provided a solid foundation for building a scalable SaaS application.
If you're building a Shopify app, consider these recommendations:
Remember that building a multi-tenant application requires careful consideration of data isolation and security at every level of your application.
Happy Coding!