Authenticate a server-side rendered embedded app using Rails and Turbolinks
This tutorial shows you how to convert your multi-page SSR app to use authentication based on session tokens with Turbolinks.
RequirementsAnchor 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 patternAnchor 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:
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 appAnchor link to section titled "Step 2: Enable Turbolinks on your app"
turbolinksgem to your Gemfile:
turbolinkspackage 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
Step 3: Create a splash pageAnchor 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.
SplashPageControlleralong with a default index action and view:
splash_page#indexthe default root route for your app. Update the following code in your
Indicate a loading status in your splash page index view. Update
app/views/splash_page/index.html.erbto match the following code:
SplashPageControllerbehave as the default embedded app
app/controllers/splash_page_controller.rbto match the following code:
Protect the default
home_controller.rbto 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 tokensAnchor link to section titled "Step 4: Fetch and store session tokens"
Create a Shopify App Bridge instance.
Fetch a session token and cache it.
Install event listeners on the
turbolinks:renderevents to add an
Install event listeners to add an
Authorizationrequest header on the following events:
Use Turbolinks to navigate to the
Add the following
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
Import the library method
shopify_app.js, include the following methods that fetch and store a session token every two seconds:
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.
shopify_app.js, add event listeners to the
turbolinks:renderevents. Set an
"Authorization": "Bearer <session token>"header during these events:
shopify_app.js, edit the
DOMContentLoadedevent listener to add the following instructions:
After a session token is retrieved,
Turbolinks.visit(data.loadPath) visits the
load_path parameter defined in
Your app continues to retrieve session tokens every two seconds.
Step 5: Request authenticated resourcesAnchor 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
For demo purposes, we have created two additional authenticated controllers:
WidgetsController. The following steps describe how to create the
ProductsController and add a navigation link to the Home view.
ProductsControllerusing the Rails generator:
Add authentication to the
Create a view for the
app/views/products/index.html.erbto match the following code:
AuthenticatedControllerto authenticate pages of your app that are deep linked. This concern is available in Shopify App version 17.1.0:
app/views/home/index.html.erbto 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 updatedAnchor 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
The following sections show a Ruby implementation that subscribes to the webhook and updates the records.
Set up the webhookAnchor link to section titled "Set up the webhook"
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 uninstalledAnchor 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 jobAnchor 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 jobAnchor link to section titled "Enqueue the background job"
RegisterWebhooksForActiveShops background job to apply the webhook registration. For details on enqueuing ActiveJobs on Rails, refer to the Rails guides.