「アクセストークンは、1時間で切れる。」の文字と、60分のタイマーが描かれたカード、引換券のイラスト

Shopifyアプリのアクセストークンが「1時間で切れる」ものに。2027年1月までに必要なアプリ側の対応まとめ

私たちの会社では、自社サービスやお客さまのストアのために、Shopifyアプリの開発をしています。

そのShopifyアプリまわりで、いま大事な変更が進んでいます。アプリがストアのデータを読み書きするときに使う「アクセストークン」が、ずっと使えるものから、1時間で期限が切れるものに変わります。

Shopify App Storeなどで配布している公開アプリは、2027年1月1日までにこの新しいトークンへ切り替える必要があります。切り替えないままだと、App Storeに掲載されなくなり、2027年4月1日からはAPIのリクエストそのものが拒否されるようになります。

この記事では、何が変わるのか、どのアプリが対象なのか、アプリ側で何をすればよいのかを、なるべくかみくだいてご紹介します。Shopifyアプリを開発・運用している方はもちろん、アプリを使っているストアの運営者さまにも参考にしていただけるとうれしいです。

情報の確認日:2026年11月5日。Shopifyの発表やドキュメントは更新されることがあります。実際に作業する前に、記事の最後にある公式ドキュメントもあわせてご確認ください。

まずは結論から

  • 対象は、Admin APIを使っている公開アプリです。1つのストア専用に作るカスタムアプリや、ストアが管理画面・Dev Dashboardで自分で作ったアプリは対象外です。
  • 新しいアクセストークンの有効期限は1時間です。いっしょに受け取る「リフレッシュトークン」を使って、期限が切れる前に新しいトークンへ交換します。
  • Shopifyの公式テンプレートや公式ライブラリを使っていれば、多くの場合は設定の追加とバージョンアップで対応できます。
  • すでにインストールされているストアのトークンも、ストアに再インストールしてもらわずに、アプリ側の処理だけで新しいトークンに移行できます。

そもそも「オフラインアクセストークン」とは?

Shopifyアプリは、Shopify本体とは別のサーバーで動いているWebアプリです。アプリが注文や商品の情報を読み書きするときは、Admin APIというAPIを通じてShopifyとやりとりします。そのときに「このアプリは、このストアのデータを扱ってよい」と証明するのが、アクセストークンです。

アクセストークンには、大きく分けて2つの種類があります。

  • オンラインアクセストークン:ストアのスタッフがアプリの画面を開いているあいだに使うトークンです。そのスタッフのログインと結びついていて、24時間たつか、ログアウトすると使えなくなります。
  • オフラインアクセストークン:誰もアプリの画面を開いていないときにも使えるトークンです。注文が入ったときのWebhookの処理や、夜中に動く定期処理など、裏側の仕事で使います。

今回変わるのは、後者のオフラインアクセストークンです。これまでは、アプリをインストールしたときに一度もらえば、基本的にはアンインストールされるまでずっと使えました。いわば期限のない合鍵のようなものです。

何が変わるの?

新しいオフラインアクセストークンは、ホテルのカードキーに少し似ています。

  • アクセストークン(カードキー):有効期限は1時間です。期限が切れると、APIのリクエストに使えなくなります。
  • リフレッシュトークン(引換券):アクセストークンといっしょに受け取ります。Shopifyに渡すと、新しいアクセストークンと交換してもらえます。有効期限は90日です。

ポイントは、引換券も交換のたびに新しくなることです。交換すると、新しいアクセストークンといっしょに新しいリフレッシュトークンが届くので、次の交換ではその新しいほうを使います。古いリフレッシュトークンは、新しいほうを使った時点で使えなくなります。

なぜこのような変更をするのでしょうか。期限のないトークンは、万が一外に漏れてしまうと、気づくまでずっと悪用できてしまいます。期限付きのトークンなら、漏れても1時間ほどで使えなくなります。お店と、お店のお客さまの情報を守るための、セキュリティの強化というわけです。

いつまでに対応すればいい?

これまでに発表されたスケジュールをまとめると、次のとおりです。

  • 2025年12月:期限付きのオフラインアクセストークンを選べるようになりました(この時点では任意)。
  • 2026年4月1日:この日以降に作られた新しい公開アプリは、期限付きトークンが必須になりました。
  • 2027年1月1日:すべての公開アプリが対象になります。未対応のアプリはShopify App Storeに掲載されなくなり、新しくインストールできなくなります。すでにインストールされているストアでは、4月1日までは動き続けます。
  • 2027年1月15日:未対応のアプリを使っているストアの管理画面に、サービスが止まるおそれがあることを知らせる警告が表示されます。
  • 2027年4月1日:期限のないトークンを使ったAdmin APIのリクエストが、エラー(HTTP 403)で拒否されるようになります。

当初は「2027年1月1日から認証エラーになる」と案内されていましたが、2026年10月27日の更新で、上のように段階的に止まるスケジュールになりました。とはいえ、1月1日を過ぎると新しいお客さまにインストールしてもらえなくなるので、実質的な締め切りは2027年1月1日と考えておくのが安心です。

対象になるアプリ・ならないアプリ

対象になるアプリ

  • Shopify App Storeで公開しているアプリ
  • App Storeには載せず、URLを知っている人だけがインストールできる形で配布している公開アプリ

どちらも、GraphQL Admin APIやREST Admin APIを使っている場合が対象です。

対象にならないアプリ

  • 1つのストア専用に作るカスタムアプリ
  • ストアが管理画面やDev Dashboardで、自分で作ったアプリ

私たちがお客さまのストア専用に作っているカスタムアプリも、こちらに当てはまります。カスタムアプリは、これまでどおり期限のないトークンを使い続けられるので、急いで対応する必要はありません。

アプリ側で必要な対応

やることを順番に並べると、次の6つです。作り方ごとの具体的な方法は、このあとの章でご紹介します。

1.新しくインストールされたストアで、期限付きのトークンを受け取る

トークンを受け取るリクエストに、「期限付きのトークンをください」という指定(expiring=1)を加えます。公式テンプレートなら、設定を1行足すだけです。

2.トークンの保存先を増やす

これまではアクセストークンを1つ保存しておけば済みましたが、これからは次の4つを保存します。

  • アクセストークン(access_token)
  • アクセストークンの有効期限(expires_in。秒数で届きます)
  • リフレッシュトークン(refresh_token)
  • リフレッシュトークンの有効期限(refresh_token_expires_in)

多くの場合、データベースに列を追加する作業が必要になります。リフレッシュトークンも、アクセストークンと同じくらい大切な情報です。暗号化して保存するなど、同じように丁寧に扱ってください。

3.期限が切れる前に、新しいトークンに交換する

アクセストークンの期限(1時間)が切れる前に、リフレッシュトークンを使って新しいトークンに交換します。交換したら、届いた新しいアクセストークンとリフレッシュトークンの両方で、保存している値を上書きします。

気をつけたいのが、同じストアのトークンを、複数の処理が同時に交換しようとするケースです。たとえばWebhookの処理と定期処理が同じタイミングで動くと、片方が受け取ったトークンがすぐに無効になってしまうことがあります。同じストアの交換は1つずつ行うように、ロックをかけるなどの工夫をしておくと安心です。

また、しばらくAPIを使っていないストアでも、90日以内に1回は交換しておきます。リフレッシュトークンの期限が切れてしまうと、ストアのスタッフにアプリを開き直してもらうまで、裏側の処理を再開できなくなるためです。

4.すでにインストールされているストアのトークンを移行する

いちばん気になるのが、すでにアプリを使ってくださっているストアのことだと思います。安心していただきたいのは、ストアにアプリを再インストールしてもらう必要はない That's it.

保存している期限のないトークンをShopifyに渡すと、期限付きのトークンとリフレッシュトークンに交換してもらえます。ストアのスタッフがアプリを開いていなくても、アプリのサーバーだけで移行できます。

ただし、交換した時点で、古いトークンは使えなくなります。古いトークンを別の場所にも保存している場合は、そちらも忘れずに切り替えてください(この点は「見落としやすいポイント」の章でもう少し詳しくお話しします)。

交換の応答を受け取りそこねてしまった場合でも、7日以内であれば、同じリクエストをもう一度送ると同じトークンを受け取り直せます。とはいえ、届いた値はすぐに保存する作りにしておきましょう。

5.うまくいかないときに、認証をやり直せるようにする

次のようなエラーが返ってきたら、トークンを取得し直す流れを用意しておきます。

  • リフレッシュトークンでの交換が、401で失敗した:リフレッシュトークンの期限切れや、使用済みのトークンを送ったことなどが原因です。
  • Admin APIが403で、「Non-expiring access tokens are no longer accepted for the Admin API」というメッセージを返した:期限のないトークンが拒否されています(2027年4月以降)。

なお、アプリに必要な権限(アクセススコープ)が足りないときにも403が返ります。ステータスコードだけで判断せず、メッセージも確認するのがおすすめです。

認証のやり直しは、Shopifyの管理画面に埋め込むタイプのアプリならトークン交換(token exchange)をもう一度行い、埋め込まないタイプのアプリならOAuthの認可画面へ案内します。

6.移行が終わったかを確認する

Dev Dashboardでアプリの「Logs(ログ)」を開き、「Type」を「GraphQL request」に、「Token type」を「Offline, non-expiring」に絞り込みます。何も表示されなければ、期限のないトークンでのリクエストは残っていません。REST Admin APIも使っている場合は、「Type」を「REST request」にして同じように確認します。

作り方別:具体的な対応方法

Shopifyの公式テンプレート(React Router・Remix)で作っている場合

@shopify/shopify-app-react-router haha. @shopify/shopify-app-remixを使っている場合は、shopify.server.ts of shopifyApp()に設定を1つ足して、デプロイし直します。トークンの受け取りと保存、期限前の交換は、テンプレートが自動で行ってくれます。

// app/shopify.server.ts
const shopify = shopifyApp({
  // ...
  future: {
    expiringOfflineAccessTokens: true,
  },
});
shopify app deploy

あわせて、セッションの保存先に、有効期限とリフレッシュトークンを保存できるかも確認します。Prismaを使っている場合は、Sessionモデルに次の列があるかを見てみてください。

// prisma/schema.prisma
model Session {
  // ...
  expires             DateTime?
  refreshToken        String?
  refreshTokenExpires DateTime?
}

この設定のあとは、ストアのスタッフがアプリを開いたタイミングで、順に新しいトークンに切り替わっていきます。しばらくアプリを開いていないストアもあるはずなので、前の章の「4.すでにインストールされているストアのトークンを移行する」もあわせて行うのがおすすめです。移行のリクエストは、このあとの「認証を自前で実装している場合」の例を参考にしてください。

なお、最近Shopify CLIで新しく作ったアプリでは、この設定がはじめから入っています。

Ruby on Railsで作っている場合

私たちの会社でもRailsでShopifyアプリを作ることが多いのですが、公式のgemでは、shopify_app 23.0.0とshopify_api 16.0.0から期限付きトークンに対応しています。どちらもメジャーバージョンアップなので、対応するRubyのバージョンなど、ほかの変更点もCHANGELOGで確認してから上げるのがおすすめです。

大まかな手順は次のとおりです。

  1. ショップのモデルに、有効期限とリフレッシュトークンの列を追加します。rails generate shopify_app:shop_model --skipでマイグレーションを作れます。
  2. ショップのモデルでShopifyApp::ShopSessionStorageを使います。非推奨になったShopSessionStorageWithScopesを使っている場合は、置き換えます。
  3. 設定で、期限付きのトークンを有効にします。
# config/initializers/shopify_app.rb
ShopifyApp.configure do |config|
  # ...
  config.check_session_expiry_date = true
end

ShopifyAPI::Context.setup(
  # ...
  expiring_offline_access_tokens: true,
)

Webhookや定期処理では、shop.with_shopify_session do ... endの中でAPIを呼べば、期限が切れているときに自動で交換してくれます。同時に交換が走らないよう、データベースの行ロックを使う作りにもなっています。リフレッシュトークン自体の期限が切れているときはShopifyApp::RefreshTokenExpiredErrorが発生するので、ストアにアプリを開いてもらうよう案内するなどの処理を用意しておきます。

すでにインストールされているストアは、設定を変えただけでは古いトークンのままです。ShopifyAPI::Auth::TokenExchange.migrate_to_expiring_tokenを使って、1店舗ずつ移行するジョブを作ります。

Shop.where(refresh_token: nil).find_each do |shop|
  new_session = ShopifyAPI::Auth::TokenExchange.migrate_to_expiring_token(
    shop: shop.shopify_domain,
    non_expiring_offline_token: shop.shopify_token
  )
  Shop.store(new_session)
rescue ShopifyAPI::Errors::HttpResponseError => e
  Rails.logger.error("#{shop.shopify_domain}: #{e.message}")
end

この移行は、ストアごとに一度きりで、元には戻せません。まずは開発ストアで試してから、本番のストアに広げていくと安心です。

認証を自前で実装している場合

公式テンプレートやライブラリを使わずに認証を実装している場合は、次のように対応します。リクエストの送り先は、どれもhttps://{shop}.myshopify.com/admin/oauth/access_token Yes.

トークンを受け取るときは、トークン交換(token exchange)でも、OAuthの認可コードの交換でも、リクエストにexpiring=1を加えます。次は、認可コードを交換する場合の例です。

curl -X POST "https://{shop}.myshopify.com/admin/oauth/access_token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "client_id={client_id}" \
  -d "client_secret={client_secret}" \
  -d "code={authorization_code}" \
  -d "expiring=1"

期限の前に交換するとき what? grant_type=refresh_tokenを指定して、保存しているリフレッシュトークンを送ります。

curl -X POST "https://{shop}.myshopify.com/admin/oauth/access_token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "client_id={client_id}" \
  -d "client_secret={client_secret}" \
  -d "grant_type=refresh_token" \
  -d "refresh_token={refresh_token}"

すでにあるトークンを移行するときは、保存している期限のないトークンをsubject_tokenに入れて送ります。

curl -X POST "https://{shop}.myshopify.com/admin/oauth/access_token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=urn:ietf:params:oauth:grant-type:token-exchange" \
  -d "client_id={client_id}" \
  -d "client_secret={client_secret}" \
  -d "subject_token={non_expiring_offline_token}" \
  -d "subject_token_type=urn:shopify:params:oauth:token-type:offline-access-token" \
  -d "requested_token_type=urn:shopify:params:oauth:token-type:offline-access-token" \
  -d "expiring=1"

どの応答にもaccess_token / expires_in / refresh_token / refresh_token_expires_inが入っているので、4つとも保存します。

見落としやすいポイント

トークンを、ほかのシステムにもコピーしていませんか?

たとえば、売上をスプレッドシートやBIツールに集計するスクリプトや、在庫を連携するバッチなどに、アプリのアクセストークンをそのまま設定しているケースです。期限付きのトークンに切り替えると、こうしたコピーは1時間で使えなくなります。さらに、移行した時点で古いトークンも使えなくなります。

移行の前に、トークンがどこで使われているかを洗い出しておきましょう。トークンの交換はアプリのサーバー1か所で行い、ほかのシステムはアプリのサーバーを通してAPIを呼ぶ形にしておくと、交換がぶつかることもなく安心です。

「トークンはずっと使える」前提で書かれたコード

起動時にトークンを一度だけ読み込んで持ち続ける、長時間かかるジョブの途中でトークンを読み直さない、といった作りになっていると、処理の途中で期限が切れてしまいます。APIを呼ぶ直前に有効期限を確かめ、期限が近ければ交換してから呼ぶ作りにしておくと安心です。

ログやエラー通知に、トークンが残っていないか

リフレッシュトークンは、90日のあいだ新しいトークンを受け取り続けられる大切な情報です。エラー通知サービスやログに、トークンやリクエストの中身がそのまま記録されていないかも、この機会に確認しておくとよいと思います。

新しい選択肢:アプリ専用のアクセストークン

2026年10月の更新では、公開アプリが裏側の処理で使える「アプリ専用のアクセストークン(application-only access tokens)」という仕組みも加わりました。あらかじめDev Dashboardに公開鍵を登録しておき、秘密鍵で署名したリクエストを送ると、最大1時間有効なトークンを受け取れます。リフレッシュトークンを保存したり交換したりする必要がないので、Webhookや定期処理が中心のアプリでは、こちらのほうがシンプルに作れるかもしれません。

アプリを使っているストアの運営者さまへ

ここまではアプリを作る側のお話でしたが、ストアを運営している方にも少しだけ関係があります。

  • App Storeからインストールしたアプリの対応は、それぞれの開発元が行うものです。ストア側で設定を変えたり、アプリを再インストールしたりする必要は、基本的にありません。
  • 2027年1月15日以降、管理画面に警告が表示されたアプリがあれば、開発元に対応の予定を問い合わせてみてください。
  • 制作会社などに作ってもらった、ストア専用のカスタムアプリは対象外です。

instead

アクセストークンの期限付き化は、お店とお客さまの情報を守るための大切な変更です。公式のテンプレートやライブラリを使っていれば、作業そのものはそれほど大きくありません。ただ、すでにインストールされているストアの移行や、トークンを使っているほかのシステムの洗い出しなど、アプリによっては思わぬところに手間がかかることもあります。

2027年1月1日まで、残りはおよそ2か月です。早めに確認しておくと、年末年始を落ち着いて迎えられると思います。

私たちの会社では、Shopifyアプリの開発や既存アプリの改修、テクニカルコンサルも承っております。「自分たちのアプリが対象かどうかわからない」「移行の作業をお願いしたい」といったご相談も、 here からお気軽にお問い合わせください。

Shopifyアプリの基本的な仕組みについては、「Shopifyアプリ開発方法入門」の記事でもご紹介しています。あわせてご覧ください。

reference link

article category