shopify_app Ruby Gem

repository·main·Indexed 23 days ago

https://github.com/shopify/shopify_app

A Rails engine and set of tools for building Shopify applications embedded in the Shopify Admin. It provides generators, modules, and mixins to handle OAuth 2.0, session token authentication, and integration with Shopify App Bridge. The gem is designed to be used in conjunction with the Shopify CLI and includes the shopify_api gem for managing API versioning and deprecations.

Tokens
21.9K
Snippets
63
Records
122
Agent score
83%

What's inside shopify_app

  1. Overview of the Shopify App gem

    main
    The shopify_app gem is a Rails engine designed to build applications that can be embedded in the Shopify Admin. It provides the necessary Rails engine, generators, modules, and mixins to implement OAuth with Shopify and secure embedded apps using session tokens. It is highly recommended to use this gem in conjunction with the Shopify CLI.
  2. Configure Content Security Policy (CSP) for embedded apps

    main

    When using the EmbeddedApp functionality (via EnsureHasSession with embedded_app: true), the following CSP directives are automatically configured to allow the app to function within the Shopify Admin:

    1. frame-ancestors: Allows embedding from the current shop domain (e.g., https://example.myshopify.com) and Shopify's unified admin domain (e.g., https://admin.shopify.com).
    2. script-src: Allows 'self', https://cdn.shopify.com/shopifycloud/app-bridge.js, and any other sources you explicitly add in your controller.
  3. How Script Tag Creation and App Block Detection works

    main

    Script Tag Creation

    Script tags are created via a background job, similar to how Webhooks are handled in ShopifyApp.

    App Block Detection

    When template_types are specified in the script tag configuration, ShopifyApp performs a capability check. It verifies if the store's active theme supports app blocks for the provided template types. If the theme does not support app blocks for any of the specified types, ShopifyApp automatically creates the script tags as a fallback. This allows your app to use modern app blocks when possible and revert to script tags only when necessary.

  4. Manage shop-specific webhooks using ShopifyApp::WebhooksManager

    main

    If you need shop-specific webhooks (e.g., different topics for different shops), you can manage them via the ShopifyApp.configure block. ShopifyApp will automatically queue a background job during the OAuth callback or token exchange to ensure the specified webhooks exist for that shop.

    Configuration Options

    • Basic Subscription: Define topic and path.
    • Field Filtering: Use fields to receive only specific fields (note: you still receive a request on every update).
    • Metafields: Use metafield_namespaces to include metafield data. If using fields, you must also include metafields in that array.
    • Webhook Filters: Use the filter parameter to apply Shopify's webhook filters (e.g., price thresholds).
    • Job Namespacing: Use webhook_jobs_namespace to change the directory where webhook jobs are located (e.g., shopify/webhooks).

    Delivery Methods

    You can also target external services:

    • Amazon EventBridge: Set delivery_method: :event_bridge and provide the ARN as the path.
    • Google Cloud Pub/Sub: Set delivery_method: :pub_sub and provide a path in the format pubsub://[PROJECT-ID]:[PUB-SUB-TOPIC-ID].

    Note: For EventBridge and Pub/Sub, you must implement your own handler to fetch and process webhooks from the queue.

    ShopifyApp.configure do |config|
      config.webhook_jobs_namespace = 'shopify/webhooks'
      config.webhooks = [
        {
          topic: 'products/update',
          path: 'api/webhooks/products_update',
          fields: ['title', 'vendor'],
          filter: "variants.price:>=10.00"
        },
        {
          topic: 'orders/create',
          path: 'api/webhooks/orders_create',
          metafield_namespaces: ['app-namespace'],
        },
        {
          delivery_method: :event_bridge,
          topic: 'carts/update',
          path: 'arn:aws:events....'
        },
        {
          delivery_method: :pub_sub,
          topic: 'carts/update',
          path: 'pubsub://project-id:pub-sub-topic-id'
        }
      ]
    end
  5. Understand OAuth authentication types

    main

    The Shopify App gem supports two primary OAuth flows. Choosing the right one depends on your app type:

    1. Token Exchange (Recommended for Embedded Apps):

      • Uses Shopify managed installation.
      • Exchanges a user's session token (Shopify ID token) for an access token.
      • Faster authorization with no redirects, preventing UI flickering.
      • Access scope changes are handled automatically by Shopify.
    2. Authorization Code Grant Flow (For Non-Embedded Apps):

      • Requires redirecting the user to Shopify for installation/authorization.
      • The app is responsible for managing installations and access scope changes.
      • Suitable for apps that do not run inside the Shopify admin interface.
  6. Manage Shopify API versioning and deprecations

    main
    The Shopify App gem includes the shopify_api gem, which allows you to specify and update the Shopify API version your app uses. The included gem also surfaces warnings to your Rails application regarding deprecated endpoints and GraphQL fields, helping you stay compliant with Shopify's versioning practices.
  7. How Frame Ancestors are handled for embedded apps

    main

    When you include the ShopifyApp::FrameAncestors controller concern (typically via ShopifyApp::Authenticated), the gem automatically configures the frame-ancestors directive in your Content Security Policy (CSP). This ensures your app can be embedded in the Shopify admin by allowing the following hosts:

    1. The current_shopify_domain (or *.myshopify.com if the domain is not present).
    2. https://admin.shopify.com.
  8. Configure Session Storage

    main

    The gem handles session persistence. You can use different storage strategies depending on your environment and needs:

    • Shop (offline) token storage: Standard storage for shop-level access.
    • User (online) token storage: Standard storage for user-level access.
    • In-memory Session Storage: Useful for testing environments where persistence is not required.
    • Custom Session Storage: You can implement your own storage by using ShopifyApp::SessionRepository.

    Custom Session Storage Requirements

    When implementing custom storage, ensure you adhere to the required interface to maintain compatibility with the gem's session management logic.

  9. How EnsureHasSession manages sessions and security

    main

    When you include EnsureHasSession, several private concerns are automatically applied to handle the following:

    • LoginProtection: Sets up and tears down the session. For embedded apps, it loads the session from the Authorization header (session tokens via App Bridge). For non-embedded apps, it loads the session from cookies.
    • Localization: Saves I18n localization to the session for consistent translations.
    • CSRFProtection: Implements Rails' protect_from_forgery unless a valid session token is present.
    • EmbeddedApp: If embedded_app is configured as true, it automatically handles P3P headers and Content Security Policy (CSP) directives.
    • EnsureBilling: If billing is enabled, it queries and enforces active payments for the session.
    • ShopAccessScopesVerification: Validates that session scopes match your app configuration.
  10. Understand Shopify access token types (Shop vs User)

    main

    Shopify apps use two primary types of access tokens (sessions):

    1. Shop (offline access): Linked to the store itself. These are intended for long-term access without user interaction, making them ideal for background jobs or maintenance tasks.
    2. User (online access): Linked to an individual user on a store. These are meant for active user interactions through the web interface.
  11. Understand Session types: Shop (offline) vs User (online)

    main

    The shopify_app gem uses sessions to manage contextual API calls. There are two primary types of sessions:

    1. Shop (offline) sessions: Used for background tasks or when the app needs to act on behalf of a shop without a user being present. These use offline access tokens.
    2. User (online) sessions: Used when the app needs to act on behalf of a specific user within a shop. These use online access tokens and are tied to a user ID.

    The gem manages the persistence of these sessions via a session repository.

  12. Make authenticated API requests after authorization

    main

    Once an app is installed and permissions are granted, a session record is stored in either SessionRepository#shop_storage or SessionRepository#user_storage (if online sessions are enabled).

    To make authenticated API calls to Shopify, use ShopifyApp's ActiveSupport controller concerns. These concerns provide helper methods to retrieve the active session token from the repository automatically.