RORK LABJP
MAX — Rork Max is built on Claude Code and Claude Opus 4.6, generating native Swift apps directly instead of React NativeAPPLE — Rork Max targets the whole Apple ecosystem: iPhone, iPad, Apple Watch, Apple TV, Vision Pro, and iMessageWORKFLOW — In practice, users settle into letting the AI scaffold while they rewrite the state management and data layer themselvesSEED — Rork raised a $15M seed led by Left Lane Capital in April, with Peak XV, True Ventures, and a16z Speedrun joiningPAPERLINE — Rork acquired app builder Paperline and says it will stay acquisitive to bring in engineering talentREVIEW — Three-month revisit reviews are growing, clarifying where the tool shines and where it doesn'tMAX — Rork Max is built on Claude Code and Claude Opus 4.6, generating native Swift apps directly instead of React NativeAPPLE — Rork Max targets the whole Apple ecosystem: iPhone, iPad, Apple Watch, Apple TV, Vision Pro, and iMessageWORKFLOW — In practice, users settle into letting the AI scaffold while they rewrite the state management and data layer themselvesSEED — Rork raised a $15M seed led by Left Lane Capital in April, with Peak XV, True Ventures, and a16z Speedrun joiningPAPERLINE — Rork acquired app builder Paperline and says it will stay acquisitive to bring in engineering talentREVIEW — Three-month revisit reviews are growing, clarifying where the tool shines and where it doesn't
Articles/Dev Tools
Dev Tools/2026-06-21Advanced

Where Should Your Rork App Store Auth Tokens? expo-secure-store and a Biometric Gate

How I moved a Rork-generated app's auth tokens out of AsyncStorage into expo-secure-store and put a biometric check in front of every read — including the size limit and sign-out gotchas I hit in production.

Rork502expo-secure-store2authentication4security5biometrics2

Premium Article

When you run a handful of apps for long enough as an indie developer, you eventually notice that the riskiest line of code is usually the first one you ever wrote — and never touched again. For me it was the auth token. The login flow Rork generated wrote both the access and refresh tokens straight into AsyncStorage. It worked, so it sat there for six months.

AsyncStorage is not encrypted. On Android the values live in a plain SQLite store; on iOS they get some protection but not the strength you'd consciously choose for a long-lived secret. If you assume a rooted or jailbroken device, or a leaky backup, plaintext tokens are simply not where credentials belong.

This article walks through moving tokens into expo-secure-store and then putting a biometric check in front of the read — migration and cleanup included. Token refresh and retry are a separate topic; here I'm focused only on storage and retrieval.

You don't have one storage — split by role

The first trap is thinking "just put everything in SecureStore." SecureStore goes through the OS keychain/keystore, so every read and write carries real cost. Push your settings and cache through it and your cold start gets visibly slower.

Split by the nature of the data instead.

DataStoreWhy
Access/refresh tokens, user secretsexpo-secure-storeA leak is immediate harm. Protected by the OS keychain/keystore
Theme, language, onboarding-complete flagsAsyncStorageLow harm if exposed. Cheap to read and write
API response cache, image metadata, bulk dataMMKV / SQLiteHigh volume, needs fast access. Low secrecy

Isolating only the tokens in SecureStore narrows the attack surface considerably while keeping startup overhead minimal.

The basics, and the cost of a read

If you're inside the managed Expo flow, install is one line.

npx expo install expo-secure-store

A thin wrapper pays off later when you start adding options. Keep keys as constants so a typo can't silently split your storage.

// lib/secureToken.ts
import * as SecureStore from "expo-secure-store";
 
const ACCESS_KEY = "auth.accessToken";
const REFRESH_KEY = "auth.refreshToken";
 
// iOS: decryptable only after unlock, never migrates to another device
// Android: AES-encrypted and held in the 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);
}

The default for keychainAccessible is WHEN_UNLOCKED, but I usually reach for the *_THIS_DEVICE_ONLY variants. It's a deliberate statement that the token must not travel to another device through iCloud Keychain or a backup. If you genuinely need to refresh tokens in the background, loosen it to AFTER_FIRST_UNLOCK_THIS_DEVICE_ONLY — but decide that from the requirement, not by default.

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
A decision rule for splitting tokens, settings, and cache across SecureStore, AsyncStorage, and MMKV
Putting biometric auth in front of the token read, with a fallback path for lockouts
A run-once migration off AsyncStorage and a sign-out routine that actually clears the device
Secure payment via Stripe · Cancel anytime

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Rork Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

Related Articles

Dev Tools2026-04-02
Complete Security Implementation Guide for Rork Apps — Biometrics, Encryption, Secure Storage & Certificate Pinning
Harden your Rork app for production: biometric auth, AES encryption, secure storage, certificate pinning, jailbreak detection, and ATT — with working code.
Dev Tools2026-06-22
Hardcoding Your OpenAI Key in a Rork (Expo) App Means It Gets Stolen — Slip a Thin Worker Proxy In Between
Embed an OpenAI or Gemini API key directly in the Expo app Rork generates and it can be extracted from the shipped binary. Here is why a key inside an app is never secret, plus a minimal Cloudflare Workers proxy that hides it (streaming passthrough included), simple abuse controls, and key rotation that needs no app review.
Dev Tools2026-05-09
5 Things to Check When Google Sign-In Throws redirect_uri_mismatch in Your Rork App
When your Rork app keeps throwing redirect_uri_mismatch on Google Sign-In, the gap is almost always between Google Cloud Console and your Expo config. Here are 5 checks that resolve it for good.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →