◉RORK LABEN
●GPT-6.1 SOL — Rork のモデルメニューに追加(09-29)。Low/Medium/High を選べ、Pro・Max に含まれます●SONNET 5.5 — UI づくりが得意で、Sonnet 5 より出力が速いモデルが選べます(09-28)●SONNET 4.5 — Claude API での提供終了は 11/30、残り27日。API 連携を足したアプリは移行先の確認を●SDK 58 — React Native 0.88 に更新されました。Android のリリース版で R8 が既定オンになり、iOS は SceneDelegate を生成します●OBSERVE — EAS Observe がネイティブクラッシュも記録します(SDK 57.0.21 以降・10/07)●NEW — 起動広告が、背面から戻った回にしか出ていませんでした。「前面に戻った」合図が、…●GPT-6.1 SOL — Rork のモデルメニューに追加(09-29)。Low/Medium/High を選べ、Pro・Max に含まれます●SONNET 5.5 — UI づくりが得意で、Sonnet 5 より出力が速いモデルが選べます(09-28)●SONNET 4.5 — Claude API での提供終了は 11/30、残り27日。API 連携を足したアプリは移行先の確認を●SDK 58 — React Native 0.88 に更新されました。Android のリリース版で R8 が既定オンになり、iOS は SceneDelegate を生成します●OBSERVE — EAS Observe がネイティブクラッシュも記録します(SDK 57.0.21 以降・10/07)●NEW — 起動広告が、背面から戻った回にしか出ていませんでした。「前面に戻った」合図が、…
記事一覧/開発ツール
⬡ 開発ツール/2026-06-21上級

Rork アプリの認証トークンはどこに保存すべきか — expo-secure-store と生体認証ゲートの設計

Rork で生成したアプリの認証トークンを AsyncStorage から expo-secure-store へ移し、生体認証を読み出しの前段に挟むまでの設計をまとめました。サイズ制限や失効処理など、運用で踏んだ落とし穴も添えています。

Rork611expo-secure-store3認証15セキュリティ15生体認証3

✦ プレミアム記事

個人開発で複数のアプリを長く運用していると、最初の実装が一番危ういまま残っていることに、ある日ふと気づきます。私の場合は認証トークンでした。Rork に「ログイン機能を付けて」と頼んで生成されたコードは、アクセストークンとリフレッシュトークンをそのまま AsyncStorage に書き込んでいたのです。動くので半年放置していました。

AsyncStorage は暗号化されていません。Android では端末内のプレーンな SQLite に、iOS では保護はされるものの開発者が意図した強度ではない場所に、文字列がそのまま残ります。root 化・脱獄された端末やバックアップ経由で読み出せてしまう前提で考えると、長期保存するトークンの置き場所としては適切ではありません。

ここでは、私自身が実際にたどった手順——トークンの保存先を expo-secure-store に移し、さらに「読み出しの前に生体認証を挟む」ところまで——を、移行と後始末も含めて設計としてまとめます。トークンのリフレッシュやリトライそのものは別の主題なので、「保存と取り出し」に絞ります。

保存先は一つではない — 役割で住み分ける

まず混乱しやすいのは「全部 SecureStore に入れればいい」という発想です。SecureStore は OS のキーチェーン/キーストアを経由するため、読み書きのたびにそれなりのコストがかかります。設定値やキャッシュまで入れると、起動時の取り出しが目に見えて遅くなります。

データの性質で置き場所を分けるのが現実的です。

データ保存先理由
アクセス/リフレッシュトークン、ユーザー秘密鍵expo-secure-store漏洩が即被害につながる。OS のキーチェーン/キーストアで保護される
テーマ、言語、オンボーディング完了フラグなどの設定AsyncStorage漏れても害が小さい。読み書きが軽い
API レスポンスのキャッシュ、画像メタなど大量データMMKV / SQLite件数が多く高速アクセスが要る。秘匿性は低い

トークンだけを SecureStore に隔離する。これだけで攻撃面はかなり狭まりますし、起動時のオーバーヘッドも最小限で済みます。

expo-secure-store の基本と、取り出しのコスト

導入は Expo の管理下なら一行です。

npx expo install expo-secure-store

ラッパーを薄く一枚かぶせておくと、後でオプションを足すときに楽になります。キーは定数にまとめ、文字列の打ち間違いを防ぎます。

// lib/secureToken.ts
import * as SecureStore from "expo-secure-store";
 
const ACCESS_KEY = "auth.accessToken";
const REFRESH_KEY = "auth.refreshToken";
 
// iOS: 端末ロック解除後のみ復号可能・他端末へ移行しない
// Android: AES で暗号化して Keystore に保管
const OPTIONS: SecureStore.SecureStoreOptions = {
  keychainAccessible: SecureStore.WHEN_UNLOCKED_THIS_DEVICE_ONLY,
};
 
export async function saveTokens(access: string, refresh: string) {
  await SecureStore.setItemAsync(ACCESS_KEY, access, OPTIONS);
  await SecureStore.setItemAsync(REFRESH_KEY, refresh, OPTIONS);
}
 
export async function getAccessToken(): Promise<string | null> {
  return SecureStore.getItemAsync(ACCESS_KEY, OPTIONS);
}
 
export async function clearTokens() {
  await SecureStore.deleteItemAsync(ACCESS_KEY);
  await SecureStore.deleteItemAsync(REFRESH_KEY);
}

keychainAccessible の既定は WHEN_UNLOCKED ですが、私は基本的に *_THIS_DEVICE_ONLY を選びます。トークンを iCloud キーチェーンやバックアップ経由で別端末に持ち出させない、という意思表示になるからです。バックグラウンドでトークンを更新する必要があるなら AFTER_FIRST_UNLOCK_THIS_DEVICE_ONLY に緩める、というように、要件から逆算して決めます。

✦

ここまでお読みいただきありがとうございます。

この記事の続きを読む

この先には、実装コードやベンチマーク結果など、実務でお役に立てる内容をご用意しています。このサイトは広告を掲載しておらず、サーバーや開発にかかる費用はメンバーの皆様のご支援で成り立っています。もしお役に立てていましたら、ご支援いただけますと大変ありがたいです。

この記事で得られること
✦SecureStore / AsyncStorage / MMKV をトークン・設定・キャッシュでどう住み分けるかの判断基準
✦生体認証を「トークンの読み出しの前」に挟む、ロックアウト時のフォールバックまで含めた実装
✦AsyncStorage からの一度だけ走る移行と、サインアウト時に端末から確実に消すための後始末
Stripe による安全な決済 · いつでもキャンセル可能
✦

この記事を購入する

この先の内容をすべてお読みいただけます。一度のご購入で、いつでも何度でもアクセスできます。このサイトは広告を掲載しておらず、皆さまのご支援がサーバー費用などの運営を支えています。

または
メンバーシップなら全記事が読み放題 →
シェア

お読みいただきありがとうございます

Rork Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • ✦コピー&ペーストで使える実装コード付き
  • ✦毎日新しい上級ガイドを追加
  • ✦¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

関連記事

⬡ 開発ツール2026-10-13
リリース前に、書き出した Expo バンドルの中から自分の鍵を探してみる
ソースに鍵がなくても、出来上がったアプリの中に鍵が残ることがあります。Expo SDK 57 で実際に expo export を実行し、バンドルの中身を grep と 60 行ほどの Node スクリプトで調べて、見つかる鍵と見つからない鍵の違いを確かめました。
⬡ 開発ツール2026-10-30
開発ビルドでは動くのに、Release の iOS だけ起動直後に落ちる — scheme を外した app.json が原因の場合の確かめ方
expo-router のアプリで app.json に scheme がないと、Release の iOS だけ起動直後に落ちることがあります。Debug と Android が無事な理由、直し方の二択、scheme を外したい場合の考え方、提出前に見つける確認手順を書き残します。
⬡ 開発ツール2026-10-27
Claude Sonnet 4.5 の API が 11 月 30 日に終わります。アプリに書いたモデル ID を、期限の前に洗い出す
Claude Sonnet 4.5 の API は 2026 年 11 月 30 日に提供終了の予定です。アプリのコードや設定に書かれたモデル ID を洗い出し、置き換えて、もう一度確かめるまでを小さなスクリプトで進めます。