API Credential Rotation

API credentials should be changed from time to time. Employees leave, API credentials can be accidentally committed to version control and wide-reaching security flaws can be discovered. While security risks, these occasions don’t often warrant downtime. Follow these steps to rotate your API credentials without any downtime for your app.


In the case of a serious security breach, your compromised API credentials should be revoked immediately before generating new ones. This will prevent a malicious attacker from accessing or modifying your users' data while you transition to new credentials. In a high-risk situation, downtime should not be avoided!

Step 1: Create a new shared secret

A new shared secret must be generated to securely communicate with Shopify’s API. Create a new shared secret from your app’s page in the Partners dashboard.

Api creds new secret

Step 2: Configure Webhooks

Webhooks are signed with your app’s shared secret to prevent forgeries. If your app uses webhooks, configure it to accept both webhooks signed with both the new shared secret and webhooks signed with the old shared secret until after revoking the old secret.


Shopify will sign webhooks with your app's oldest unrevoked shared secret. We know it can be convenient to use the same secret key configuration for both OAuth and webhook validation, but this makes it easy to incorrectly validate webhooks using only the new shared secret after following step #3.

Step 3: Configure OAuth

Access tokens requested from Shopify’s API using the new shared secret will be secure. Configure your app to use only the new shared secret for OAuth Authentication.

Step 4: Generate new Refresh Token

Many of the access tokens stored by your app will be associated with the old shared secret. New access tokens must be requested from the Shopify API to work with the new shared secret. You'll need a refresh token to generate these new access tokens. Create a refresh token from your app’s page in the Partners dashboard. Refresh tokens automatically expire after one hour

Api creds new refresh token

Step 5: Request new access tokens

For each access token stored by your application, refresh it by requesting an access token using your new shared secret and the refresh token:

POST https://SHOP_NAME.myshopify.com/admin/oauth/access_token

with the following parameters:

  • client_id (required): The API key for your app
  • client_secret (required): The new Shared Secret for your app
  • refresh_token (required): The refresh token you created from your app’s page in the Partners dashboard
  • access_token (required): The access token you would like to refresh

The refresh token is temporary, and can only be used for one hour after it has been generated.

Step 6: Revoke the old shared secret

Now your app is using the new shared secret to communicate with the Shopify API. The old shared secret can now be revoked. Revoke it from your app’s page in the Partners dashboard. Remember that revoking any secret will also remove the access tokens associated with it.

Api creds remove old secret

If your app uses Webhooks, configure it to accept Webhooks signed with the new shared secret only.

Example Implementations


The following shows a basic example implementation of Access Token rotation in the Ruby programming language.

require "rest_client"
require "json"

api_key = "public-api-key"
shared_secret = "newly-generated-shared-secret"
refresh_token = "token-generated-from-partners-dashboard"
access_token = "access-token-to-refresh"

post_data = {
  client_id: api_key,
  client_secret: shared_secret,
  refresh_token: refresh_token,
  access_token: access_token,

response = RestClient.post('https://shop.myshopify.com/admin/oauth/access_token.json', post_data)
access_token = JSON.parse(response.body)['access_token'] # abracadabra


The following shows a basic example implementation of Access Token rotation in the PHP programming language.

  $api_key = "public-api-key";
  $shared_secret = "newly-generated-shared-secret";
  $refresh_token = "refresh-token-from-partners-area";
  $access_token = "access-token-to-refresh";

  $post_data = array(
    "client_id" => $api_key,
    "client_secret" => $shared_secret,
    "refresh_token" => $refresh_token,
    "access_token" => $access_token,
  $data_string = json_encode($post_data);

  $headers = array(
    "Content-Type: application/json",
    "Accept: application/json",
    "Content-Length:" . strlen($data_string)

  $handler = curl_init('https://shop.myshopify.com/admin/oauth/access_token.json');
  curl_setopt($handler, CURLOPT_CUSTOMREQUEST, "POST");
  curl_setopt($handler, CURLOPT_POSTFIELDS, $data_string);
  curl_setopt($handler, CURLOPT_RETURNTRANSFER, true);
  curl_setopt($handler, CURLOPT_HTTPHEADER, $headers);

  $response = curl_exec($handler);

<?php echo($response) ?>
<!-- {"access_token": "abracadabra"} -->