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
Anchor link to section titled "Requirements"- You've created a public app or custom app from your Partner Dashboard.
- The app is embedded in Shopify admin.
Your app has the Shopify App gem version 17.1.0 or higher installed. The Shopify App gem version 17.0.5 and higher creates a JSON Web Token (JWT)-enabled app by default when you run the following terminal command:
You have a basic understanding of Turbolinks.
Step 1: Conversion pattern
Anchor link to section titled "Step 1: Conversion pattern"To use session tokens with your multi-page app using Turbolinks, implement the following conversion pattern:
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.
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
Install a timed event that continues to retrieve and cache session tokens every two seconds. This ensures that your session tokens are always valid.
Use Turbolinks to navigate to your app's authenticated home page or resource.
Step 2: Enable Turbolinks on your app
Anchor link to section titled "Step 2: Enable Turbolinks on your app"Add the
turbolinks
gem to your Gemfile:Run
bundle install
.Add the
turbolinks
package to your application.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.
Step 3: Create a splash page
Anchor link to section titled "Step 3: 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.
Create a
SplashPageController
along with a default index action and view:Make
splash_page#index
the default root route for your app. Update the following code in yourroutes.rb
file:Indicate a loading status in your splash page index view. Update
app/views/splash_page/index.html.erb
to match the following code:Make the
SplashPageController
behave as the default embedded appHomeController
by updatingapp/controllers/splash_page_controller.rb
to match the following code:Protect the default
HomeController
by inheritingAuthenticatedController
. Updatehome_controller.rb
to match the following code: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.
Step 4: Fetch and store session tokens
Anchor link to section titled "Step 4: 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
andturbolinks:render
events to add anAuthorization
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
.
Add the following
load_path
parameter toapp/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 tohome_path
by default:Import the library method
getSessionToken
fromapp-bridge-utils
inapp/javascript/shopify_app/shopify_app.js
:In
shopify_app.js
, include the following methods that fetch and store a session token every two seconds:In
shopify_app.js
, also include the following helper method and replace'/home'
with your app'shome_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.In
shopify_app.js
, add event listeners to theturbolinks:request-start
andturbolinks:render
events. Set an"Authorization": "Bearer <session token>"
header during these events:In
shopify_app.js
, edit theDOMContentLoaded
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.
Step 5: Request authenticated resources
Anchor link to section titled "Step 5: 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.
Generate a
ProductsController
using the Rails generator:Add authentication to the
ProductsController
by inheritingAuthenticatedController
:Create a view for the
ProductsController
. Updateapp/views/products/index.html.erb
to match the following code:Add the
ShopifyApp::EnsureAuthenticatedLinks
concern toAuthenticatedController
to authenticate pages of your app that are deep linked. This concern is available in Shopify App version 17.1.0: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.
Step 6: Make sure shop records are updated
Anchor link to section titled "Step 6: Make sure shop records are updated"To ensure OAuth continues to work with session tokens, your app must update its shop records when a shop uninstalls your app. An app can receive notifications of uninstall 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
Anchor link to section titled "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
Anchor link to section titled "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
Anchor link to section titled "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
Anchor link to section titled "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 server-side rendered Rails app converted using Turbolinks
- 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.