TL;DR: Make sure your app APIs and data are secure when installing your Gadget API client in a Shopify storefront by using Gadget’s built-in authorization tools, global actions to return data to unauthenticated users, and auditing your API permissions.
Keeping your APIs secure is extremely important, especially when serving data to unauthenticated users like shoppers browsing a Shopify storefront. To help developers control access to their APIs, Gadget has a built-in authorization system used to set API permissions and grant unauthenticated users access to API endpoints.
Shopify handles API authorization for the storefront slightly differently - they have two APIs:
By default, the Storefront API is unauthenticated and all users have read-only access with no sign-in credentials required. Because Shopify manages this API layer, developers building Shopify apps can simply make Storefront API requests without giving too much thought to data security.
Every Gadget app has a unique, auto-generated API client that can be installed into a Shopify storefront. This can be a great way to power unique shopping experiences. But, when building a Shopify app (or any web app) using Gadget, you are in full control of your app’s API and must ensure that your sensitive data is not accessible by unauthenticated shoppers.
That’s not to say that Gadget doesn’t help. The following is automatically done to enhance API and data security when making requests from a Shopify storefront:
Even though Gadget tries to assist you in keeping your data and APIs secure, you still need to review your APIs yourself. This involves going through a Gadget app’s unauthenticated access role to ensure that the API client installed on a storefront is secure.
The following are some rules you can follow to ensure your APIs remain secure:
DON’T give unauthenticated access to model actions containing sensitive data.
Granting read access to a model gives a role full access to every field of data stored on that model. If even one field contains sensitive data, you should not grant unauthenticated access to that model. This can include metafields or other data that should not be accessible to shoppers.
DON’T return sensitive data to unauthenticated users in global actions.
When you create a new global action in Gadget, you get control over the shape of data that will be returned when the action is called and can also leverage the built-in roles and permissions system to handle authorization. If you are granting unauthenticated users access to a global action, that action should not return any sensitive data.
The following is an example of what you should avoid doing:
Note: Because you have control over the returned fields in a global action, you could grant the unauthenticated role access to an action and check the role of the user related to the current session inside your action. Sensitive information can be included if the user role is not unauthenticated. For example, sensitive data can be returned to users who have the shopify-app-user role, which is granted to merchants using embedded admin apps. The alternative is to create separate global actions that return different sets of data, share any common code with a utility file, and then grant the global actions separate permissions.
DON’T return sensitive data in HTTP routes that don’t have some kind of custom authentication.
By default, HTTP routes in Gadget will be unsecured. You need to implement custom authentication if you want to use routes to return sensitive information. We recommend using global actions instead of HTTP routes when returning sensitive information so you can take advantage of Gadget’s authorization system.
DO create global actions that return only the data required, and allow them to be called by unauthenticated users.
Because you have complete control over the data returned from global actions, they are the recommended way to return data from models that have fields containing sensitive data. You can fetch the required data in the global action and use a `select` query to limit the fields that are fetched to exclude any sensitive fields, then return that payload to the caller.
DO grant unauthenticated users access to model read actions that have no sensitive data.
If you have a data model that does not contain any sensitive data, then it is perfectly fine to grant unauthenticated users access to that model’s API. For example, if you are building a product quiz app that is embedded in the storefront, you want users to be able to read data models storing the quiz itself, questions, answers, and recommended products. You will still want to make sure that minimum permissions are granted. You don’t want shoppers to be able to create or update quiz questions, you only want them to read records from the database.
DO use the Storefront API to fetch Shopify data (but there’s a catch).
You can still use the Shopify Storefront API to fetch Shopify data. The catch is that you need to set up Storefront API request handling yourself, as Gadget does not interface with the Storefront API. But if you only need to display data that is available in the Storefront API, this might be a solution that works for you.
DO audit your API access before deploying your app to production.
Even if you followed these steps and have been careful when developing your app, it never hurts to double-check and make sure that sensitive data is not accessible to unauthenticated users. To do this, you can use your browser’s web console or a tool like Postman to send unauthenticated requests to your Gadget app’s APIs. You should make sure that no sensitive data fields are returned and GGT_PERMISSION_DENIED errors are returned for inaccessible endpoints.
Bonus: You can add unit tests to validate the shape of data returned from your API as well as your API permissions. Read our documentation on unit testing your Gadget app to learn how to set up a unit test framework and use an unauthenticated API client to check for GGT_PERMISSION_DENIED errors. Properly written tests mean that you don’t need to always test every API endpoint manually before deploying to production.
If you mind the permissions granted to your API endpoints, use global actions to return data from models that contain sensitive data, and audit your API before deployments, you should have no problems keeping your API and data secure when making requests from the Shopify storefront. Have questions? Reach out on our developer Discord or read our docs on securing your Gadget app.