Smart Authentication for Shopify Apps

Shashank Kumar
PushOwl
Published in
7 min readMay 25, 2020

--

There is one thing which every app company does in Shopify, is to build authentication. But what if, we could do little differently. A small tweak which would not just help you authorise/authenticate a merchant but also tell you a little more. A lot of times, it’s not the account owner, but a staff or a collaborator. They log in at different times and might be using your app for different use cases. This blog is about sharing what we learnt in the last two years. And hope your comments will teach us more, and together we can build better apps for entrepreneurs.

Basics First

Let’s revise some of the concepts. A merchant can reach your app through one of the following ways:

  • Click on “Add App” button in Shopify App Store — Signup Flow
  • Come back to your app from Shopify App Admin — Relogin Flow
Signup Flow — Clicking on “Add App” button in App Store
Signup Flow — Clicking on “Add App” button in App Store
Relogin Flow — From Shopify Admin > Apps

In both the scenarios, Shopify is going to hit your backend on the url in the App Setup.

Shopify Authentication Endpoint

There might be few other Auth flows:

  • From a dedicate signup/signin page by entering their subdomain
  • Custom Auth — Username/Password, or Google Login

The First Optimisation

Log all attempted installs and use minimum scope during signup

Every time the API Endpoint is hit, Shopify passes an identifier for the shop and an HMAC which can be verified using the App Secret Key. The identifier is sent in url parameter in format examplestore.myshopify.com. Our system strips (.myshopify.com) part, and just uses the subdomain (examplestore) as the identifier. And on every auth, I can assume all of us check our database to find if the store was already installed or not to initiate Signup or Relogin flow.

In the Signup flow, the backend will be generating a Shopify Permission Url which will add all the scopes, the app needs to perform.

A lot of times, the apps are getting installed by a staff and if the staff is not having necessary permissions, then the app install will fail without any warning to backend. There are two things which can be done here:

  • Ensure before redirecting to the Shopify OAuth keep a record in your system. We keep a record in our database as “Attempted Install” table.
  • Try to minimise the scope you initially need, if you see a lot of failed installed. Some of the optional permissions can be taken later with new permission flow (described later)
Measuring App Install Success

Monitoring and success of your signup can potentially lead to ~5% more signups

Identifying actual users

If you look at the authentication documentation for Shopify App, you will probably won’t see a way to identify subscribers. Most of us app developers use the Offline Access Method (https://shopify.dev/concepts/about-apis/authentication#offline-access) which allows apps to exchange a permanent access token with Shopify to do API calls during the time an app is installed at merchants store. We can call the shop.json API, and that gives the account owner name and email among other things to setup the authentication system in app.

Simple Auth Flow — Flowchart with offline authentication

What typically gets missed is the online access method (https://shopify.dev/concepts/about-apis/authentication#online-access). The documentation says:

An access token created with this access mode is temporary, and is guaranteed to expire after some amount of time.

Since the access token is temporary, it’s no use for most apps. But it does have one cool other feature as per the documentation:

After your app is installed, requesting this access mode will always return an access token restricted to the scopes available to the user. The app can inspect scope and associated_user_scope to determine if a user is lacking certain permissions.

Let’s dive deep on what the response actually looks like.

{
"access_token": "shtemp_btestecetoken9cfa48c8adb1eb572a4",
"scope": "write_content,read_products,read_customers",
"expires_in": 86398,
"associated_user_scope": "write_content,read_products,read_customers",
"session": "8dce9adf88757bf1eab4c771297ba2cff5e3ed87cb3ddeae95377c1944a06e78",
"associated_user": {
"id": 117977220,
"first_name": "John",
"last_name": "Doe",
"email": "contact@examplestore.com",
"account_owner": true,
"locale": "en-IN",
"collaborator": false,
"email_verified": true
}
}

Voila! We have the logged in user information in the associated_user key!

  • “account_owner”: true means the logged in user the owner. Obvious! And you should be able to match the data from shop.json API call as well
  • “collaborator”: true would mean the logged in user is a Shopify Partner. As an app developer you might want to reach out to them for collaboration.
    Sometimes your competitors spying from a real merchant store ;)
  • “account_owner”: false and “collaborator”: false would mean the person is a staff of the store.

I would suggest to log an entry in the database for each of these login events. This will potentially show you the most active user of your app. So if you want to reach out to the relevant person for let’s say an upgrade, you are actually talking to the most relevant person.

Putting Authentication and Identification Together

So how do you get the best of both world. Apparently, after you have done offline authentication, redirecting a merchant to online authentication will happen silently without clicking on “Allow” on the OAuth Screen. Which means, you can do silent online authentication. A merchant might see a quick redirect happening for a microsecond, but your backend will get all the necessary data. Here’s how a typical flow chat would look like.

Updated Authentication Flow Diagram

Don’t forget to add online auth callback url in whitelisted url

Doing things asynchronously

Exchanging Online Authentication token to get login user data and doing further processing is something which I would recommend doing on a background process. Since these additional seconds of processing means, we are delaying access to our app (not a good UX!)

Frameworks like Django have queuing systems like RabbitMQ + Celery or RoR has Sidekiq to get things done on background (or worker) servers.

Slack Notifications

At PushOwl, we stick more data in order to form a unified view of the person using the app. We send real time pings to our support team via Slack.

A typical Slack Ping

For Slack, you can utilise their Incoming Webhook feature to send real time updates.

Slack Incoming Webhook

So combine all the data in the background and send a ping to your Slack. And all it takes is a small API request to send data like this.

Attaching a screenshot of some of the field we find really useful. It helps us qualify merchants on the kind of support we need to provide to them.

Some useful fields that can be considered adding:

  • Store Created At or the age of the store
  • Shopify Plan (we exclude trial stores from our Slack Pings)
  • Signup At
  • Intercom Link (We call Intercom’s API to get one click link to start having convo with them. Every second is import when it comes to real time chat)
  • Country and Phone (In case your Sales team does calling)
  • Activity (using the login data we have stored, we can figure out how engaged a merchant is)
  • Business Metrics (In our case, subscribers gained, campaigns sent and revenue made)

Further Optimisations

Once you have stitched all this data and more, there are multiple use cases which you as an app can track during lifecycle of the app.

  • Uninstalls — When an uninstall happens you can send an extra data when was the last login. Some scenarios:
    - Last login happened few minutes back: Worth taking a look in screen recording session of the merchant (FullStory, LuckyOrange or HotJar), and see what might have caused the uninstalls (Dead Clicks, Rage Clicks etc)
    - Last login was long time away: It means the app has been dormant for quite sometime. Which means you as an app dev need to work on retention
    - Uninstall happened by different person than installation: Some other team member didn’t like your app. Maybe want to check if it was a mistake.
  • Sales Qualification: Reaching out to folks when they are actually using the app always leads to more conversion. You are not waiting for your email to be opened in that case. Tip: Send a ping to a dedicated Slack channel

Bonus: Managing Scope of Your App

One of the important aspects of the whole approach is the scope your app uses for authentication. As the app keeps evolving, potentially the app might need new permissions. Not managing the scopes can lead to following issues:

  • Old signups will see API errors since your app doesn’t have necessary permissions
  • If you start asking everyone new permissions, a staff account potentially won’t be able to access the app, if they don’t have necessary permissions 😱

Our DB schema maintains the list of permissions a store has. And if someone tries to use a new feature which needs additional scope, it redirects them to Offline Auth Flow again, and after getting the new permissions, we write it back to the DB.

Using Offline Auth to trigger new permissions

Final Notes

As the Shopify ecosystem is growing, hope to add a little value to the entrepreneurs who code so that we can support the millions of entrepreneurs who sell online. Feel free to reach out to me over email shashank@pushowl.com or my team.

And if you are looking to join a small and happy team — We are a team of 12 humans and 2 dogs looking for superheroes to join us. Our job listing is usually live at: https://angel.co/company/pushowl/jobs/

--

--

Shashank Kumar
PushOwl

Building @pushowl with a team of 12 incredible humans from 4 nations and a pampered dog.