Getting Laravel (5.2) works with Heroku for Shopify Embedded App Development

Inspired by REVENUE AFTER 3 YEARS IN THE SHOPIFY APP STORE, I start exploring the world of Shopify App Development using my favorite PHP Framework: Laravel and hosts it on Heroku. I don’t have solid idea what App I am going to code, the work that I am going to share is how I finally get Laravel basically work inside Shopify as Embed app and get it running on Heroku.

I assume you have basic understanding what is Heroku / Laravel / Shopify Embedded App (EASDK).

Setup Laravel (5.2) + Heroku

Heroku has simplified the integration with Laravel making development of Laravel software easy: Following the tutorial can get your Laravel site work on Heroku in 5 minutes. Once done, you should see a big Laravel wording at the center of the page when accessing your heroku app domain.

Create your Shopify App (Embedded App)

Once you have Laravel work on Heroku, you need to also create an App for App key / App Secret (Ref to sections about app creation on During the setup of the app, you may need to define URL path for Authentication Call back. Here is what I have for my app:


Things to notice:

  1. To let the app run as embedded mode, you need to set the Embedded Setting to Enabled.
  2. You need to define all your URL with HTTPS protocol (I will elaborate more later)
  3. Most critical URL would be the last ‘Redirection URL’

Create a Test Store as the playground

You should also prepare a clean test store as your playground unless you wanna let Shopify accidentally send notification email to any store owner that you install the test app for them.

So far you should have Laravel / Heroku / App / Test Store all setup.

Install Shopify API library to Laravel

I use this simplified Shopify API for the beginning:

Coding in Laravel

From the screenshot I provided, there is a field call Redirection URL, that is the URL that upon store owner authorize installing a Shopify App. In Laravel, you need to define a route for this, eg /authCallback


For the Laravel site, I defined these routes:

Routes in web middleware
Routes in web middleware

You can see I have written a controller call ShopifyAuthController under /app/Http/Controllers/Auth with 2 member functions:

  • access
  • authCallback

Remember to put these route inside the ‘web’ middleware otherwise you cannot use Session feature (This waste me lots of time as I overlook the comment right above the web middleware code).


The ShopifyAuthController works like this:

  1. Check is there ‘shop’ in incoming URL query, save it in session for future use if it exists.
  2. Check is there ‘access_token’ stored in session:
    • if YES
      • As long as we have access token, we can use it for Shopify API call
    • If NO
      • Run the Shopify API library to create a ShopifyAPI instance by passing App key / App Shared Secret / the current shop domain (from the URL query)
      • Using the created ShopifyAPI instance to call for the installation URL
      • Show a view (lets call this escape iframe view) that only has a JS code for a parent window redirection to the installation URL

The YES case above is easy to understanding, but for the NO case this cost me quite a lot time to get it works. As your app is running inside Shopify interface using <iframe>, for the OAuth process, the way ask Shopify to provide you access of a Shopify store, it requires calling the parent window (the page holding the iframe, ie the Shopify admin page) for such authentication call.

The outcome script:

Auth Controller
Escape iFrame View
Escape iFrame View – only contains JS to perform parent window redirection


Up to now you have done the work to handle call for Shopify authentication. The following works are to handle the callback once Shopify finish the authentication.

You need to use the data that returned from Shopify upon finishing authentication and store certain data in database for future use. Shopify redirects visitors form Shopify to your app by accessing the Redirection URL with following data:

  • Shop
  • hmac
  • code
  • timestamp

Among the URL parameters, code will be used for generating the access token that you need in future store access.

ShopifyAuthController::authCallback() : generate access token using the received code from Shopify Authentication

The code receive the shop and code query parameters, you use shop for creating a ShopifyAPI instance, and call ShopifyAPI::getAccessToken member function by passing the code for the access token generation.  Once you have the access token, save it in DB mapped with shop name (*

Installing your app to a store

You have all things almost done. Since your app is not yet shown in Shopify App Store, there is no way to access your app unless you manually access the app install link:

This will call your ShopifyAuthController::access() and then call the ShopifyAuthController::auth($shop) function for the installation URL. You should see the Shopify App installation screen. Clicking ‘Authorize’ to finish the app installation, so finally you should see your app appear in the Shopify Store App section.

Issue solving

About mixed content

I find out somehow the App that we written cannot display properly in the Shopify iframe. Using Chrome Developer Tool I can see the page request is fail due to Mixed Content. This page ( ) explained the meaning of such error, in simple, somehow the App / the Laravel site is being called with HTTP while the Shopify Adamin page is under HTTPS. Browser block the potential unsecure content causing the App cannot be loaded.

However you should also remember I mentioned the Redirection URL and other URL configuration has already be written with “https://”, isn’t that already enough? The reason of having HTTP call is due to Laravel internal routing ( eg. Redirect::to(‘a route url’) ). To solve the issue you need to config your whole Laravel to run in HTTPS mode by adding ‘URL::forceSchema(“https”);’ in app/Providers/AppServiceProvider.php:

Enforce all request run in HTTPS secure mode
Enforce all request run in HTTPS secure mode in app/Providers/AppServiceProvider.php

SSL issue and infinite loop

Once you enforced your Laravel run in HTTPS and when you access your App in Shopify, you may find out there is infinite loop happen when you access your App in Shopify Admin. It is because dyno in Heroku that handling your request is running in HTTP mode, so in Laravel application detect the request is HTTP and then perform a redirection (ref: stackoverflow , a blog for nodejs app). This phenomenon happens to all kind of App that happen on Heroku.

To solve the loop, there are lots of various approach from the internet and the way I picked is to use .htaccess for this:

.htaccess modification for stopping Heroku SSL loop issue
.htaccess modification for stopping Heroku SSL loop issue
#Normal way (in case you need to deploy to NON-heroku)
RewriteCond %{HTTPS} !=on

#Heroku way
RewriteCond %{HTTP:X-Forwarded-Proto} !https

#If neither above conditions are met, redirect to https
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

After all, the infinite loop should stop and your app should be able to run properly in Shopify App.

I write this blog after I fully setup my App to run in Shopify. I hope I didn’t miss out any detail part. Let me know does this help solving your problem and hope you can have your App run properly so as to enjoy the fun of programming Shopify App!

2 thoughts on “Getting Laravel (5.2) works with Heroku for Shopify Embedded App Development”

  1. Awesome Guide to create structure for Shopify App using Laravel. I appreciate and recommend for others to follow.

  2. Great Example of settng up and installing app in store. But if you can share more about this that would be great for developers like me who is intrested in shopify app using laravel. If you can Please shre basic app like custome form or backend type app for multiple product discount app. Both apps are simple and it would really help me to figure how app works.

Leave a Reply

Your email address will not be published. Required fields are marked *

Please Answer * Time limit is exhausted. Please reload CAPTCHA.