Authenticate a server-side rendered embedded app using Rails and Turbolinks

If you have a multi-page server-side rendered (SSR) app and you want to use session token-based authentication, then you can still use session tokens by converting your app to use Turbolinks. Turbolinks is a JavaScript library that makes your app behave as if it were a single-page app. You can use Turbolinks even if you're unsure or not yet ready to convert your app to a single-page app.

This tutorial shows you how to convert your multi-page SSR app to use authentication based on session tokens with Turbolinks.

Requirements

Conversion pattern

To use session tokens with your multi-page app using Turbolinks, implement the following conversion pattern:

  1. Create an unauthenticated controller that renders a splash page when a user visits your app. This splash page communicates to users that your app is loading.

  2. Use the splash page to do the following:

    • Create a Shopify App Bridge instance.
    • Retrieve and cache a session token within your app client.
    • Install event listeners to set an "Authorization": "Bearer <session token>" request header on the following events:
      • turbolinks:request-start
      • turbolinks:render
  3. Install a timed event that continues to retrieve and cache session tokens every two seconds. This ensures that your session tokens are always valid.

  4. Use Turbolinks to navigate to your app's authenticated home page or resource.

Use the following steps to enable Turbolinks on your app.

Steps

  1. Add the turbolinks gem to your Gemfile:

  2. Run bundle install.

  3. Add the turbolinks package to your application.

  4. If you're working with an existing app and it uses webpack to manage its manifest files, then make sure that the following line is added to app/javascript/packs/application.js. This line is provided by default in new apps.

Create a splash page

Your splash page is used to indicate that your app has begun to fetch a session token. When your app gets the token, it should navigate the user to the main view. The main view might contain protected or authenticated resources.

Steps

  1. Create a SplashPageController along with a default index action and view:

  2. Make splash_page#index the default root route for your app. Update the following code in your routes.rb file:

  3. Indicate a loading status in your splash page index view. Update app/views/splash_page/index.html.erb to match the following code:

  4. Make the SplashPageController behave as the default embedded app HomeController by updating app/controllers/splash_page_controller.rb to match the following code:

  5. Protect the default HomeController by inheriting AuthenticatedController. Update home_controller.rb to match the following code:

  6. To handle changes in access scopes requested by your app, add the following configuration to /app/config/initializers/shopify_app.rb. For more information on handling changes in access scopes, refer to the Shopify App gem.

Fetch and store session tokens

When users visit the app for the first time, you can use JavaScript to complete the following tasks on the splash page:

  • Create a Shopify App Bridge instance.

  • Fetch a session token and cache it.

  • Install event listeners on the turbolinks:request-start and turbolinks:render events to add an Authorization request header.

  • Install event listeners to add an Authorization request header on the following events:

    • turbolinks:request-start
    • turbolinks:render
  • Use Turbolinks to navigate to the HomeController.

Steps

  1. Add the following load_path parameter to app/views/layouts/embedded_app.html.erb. This parameter is used by Turbolinks to navigate back to this app when a session token has been fetched. In the following example, you're navigating to home_path by default:

  2. Import the library method getSessionToken from app-bridge-utils in app/javascript/shopify_app/shopify_app.js:

  3. In shopify_app.js, include the following methods that fetch and store a session token every two seconds:

  4. In shopify_app.js, also include the following helper method and replace '/home' with your app's home_path. The helper method navigates your app using Turbolinks. It does this by determining whether the navigation is made on the initial load of your app.

  5. In shopify_app.js, add event listeners to the turbolinks:request-start and turbolinks:render events. Set an "Authorization": "Bearer <session token>" header during these events:

  6. In shopify_app.js, edit the DOMContentLoaded event listener to add the following instructions:

After a session token is retrieved, Turbolinks.visit(data.loadPath) visits the load_path parameter defined in embedded_app.html.erb.

Your app continues to retrieve session tokens every two seconds.

Request authenticated resources

When a user visits your app, they should now briefly see a loading screen before they're taken to the Home view of your app. The Home view is authenticated by the HomeController.

For demo purposes, we have created two additional authenticated controllers: ProductsController and WidgetsController. The following steps describe how to create the ProductsController and add a navigation link to the Home view.

Steps

  1. Generate a ProductsController using the Rails generator:

  2. Add authentication to the ProductsController by inheriting AuthenticatedController:

  3. Create a view for the ProductsController. Update app/views/products/index.html.erb to match the following code:

  4. Add the ShopifyApp::EnsureAuthenticatedLinks concern to AuthenticatedController to authenticate pages of your app that are deep linked. This concern is available in Shopify App version 17.1.0:

  5. Update app/views/home/index.html.erb to include a link to the product index view:

Your app can now access the authenticated ProductsController from the HomeController using session tokens.

Make sure shop records are updated

To ensure OAuth continues to work with session tokens, your app must update its shop records in the event a shop uninstalls your app. The app can receive notifications of these events by subscribing to the app/uninstalled webhook.

The following sections show a Ruby implementation that subscribes to the webhook and updates the records.

Set up the webhook

Use the add_webhook generator from the shopify_app gem to set up the app/uninstalled webhook for the app. The following code adds the app/uninstalled webhook to your app config and creates the AppUninstalledJob job class so that you can add uninstallation handler logic.

Mark the shop record as uninstalled

To mark the record as uninstalled, you need to update the AppUninstalledJob job class. In the following example, the app marks the shop as uninstalled by deleting the Shop record:

Define a background job

You need to define a background job to ensure that shops with existing installations also have the uninstall webhook set up. In the following example, the RegisterWebhooksForActiveShop job is defined to iterate all shop records in the database and configure the webhooks.

Enqueue the background job

Enqueue the RegisterWebhooksForActiveShops background job to apply the webhook registration. For details on enqueuing ActiveJobs on Rails, refer to the Rails guides.

Sample app

Sample server-side rendered Rails app converted using Turbolinks

Next steps

  • Make authenticated requests using Axios.
  • Learn how to use helper functions to fetch a session token from Shopify App Bridge and include them in requests being made to the app backend.
  • Learn how to build a Shopify app with Rails 6, React, and Shopify App Bridge authentication.