Summary#
Expo EAS OTA 업데이트 이후 SecureStore.getItemAsync()가 null을 반환하는 현상은, 공개 문서 기준으로 볼 때 “OTA가 iOS Keychain / Android Keystore 값을 직접 삭제했다”기보다는 OTA로 배포된 JavaScript 코드가 기존 저장값을 읽는 방식과 달라졌기 때문에 발생하는 실패 모드로 정리하는 것이 안전하다.
특히 다음 변경은 위험하다.
- 기존에는
requireAuthentication: false또는 기본 옵션으로 저장했는데, OTA 후requireAuthentication: true로 읽거나 다시 저장/읽기 시작한 경우 - 기존 저장 시 사용한
keychainService와 OTA 후 읽을 때 사용하는keychainService가 달라진 경우 - SecureStore key 이름, platform 분기, auth/session migration 로직이 OTA로 바뀐 경우
- 네이티브 바이너리 변경이 필요한 SecureStore / expo-updates / SDK 변경을 OTA만으로 배포하려 한 경우
runtimeVersion정책이 느슨하거나 잘못되어, 특정 바이너리에 맞지 않는 JS 업데이트가 로드된 경우
공식 문서상 SecureStore.getItemAsync()는 저장된 값이 없거나 더 이상 사용할 수 없는 경우 null을 반환할 수 있다. 또한 requireAuthentication으로 보호된 값은 생체 인증 설정 변경 등으로 접근 불가능해질 수 있다. 따라서 이 이슈는 OTA 자체의 삭제 문제라기보다 저장 옵션·인증 조건·runtimeVersion 호환성·기존 사용자 기기 상태가 엇갈리는 문제로 다루는 것이 적절하다.
Key Points#
-
expo-secure-store는 iOS에서 Keychain Services를 사용하고, Android에서는 보안 저장 계층을 사용한다. 이는 AsyncStorage 같은 순수 JS 저장소와 다르게 OS 보안 정책과 네이티브 구현의 영향을 받는다. -
SecureStore.getItemAsync()는 해당 key에 값이 없거나 값에 접근할 수 없는 경우null을 반환할 수 있다. 앱에서는 이것이 “토큰이 사라졌다”처럼 보일 수 있지만, 실제로는 다른 key / 다른 service / 인증 불가 상태를 읽고 있을 수 있다. -
requireAuthentication옵션은 중요한 분기점이다. Expo 문서는 이 옵션으로 저장된 값이 생체 인증 정보 변경 등으로 무효화될 수 있다고 설명한다. 예를 들어 사용자가 Face ID / Touch ID / 지문 설정을 변경하면 기존 항목을 더 이상 읽지 못할 수 있다. -
keychainService는 같은 logical key라도 다른 Keychain service namespace를 만들 수 있다. 저장할 때 사용한keychainService와 읽을 때 사용한keychainService가 다르면 기존 값을 찾지 못해null처럼 보일 수 있다. -
EAS Update /
expo-updates는 기본적으로 JS bundle과 asset을 OTA로 교체하는 메커니즘이다. 네이티브 코드 변경이 필요한 경우에는 새 바이너리 배포가 필요하다. 따라서 SecureStore 네이티브 동작, Expo SDK, native module 구성 변화가 있다면 OTA만으로 해결하려 하면 안 된다. -
runtimeVersion은 어떤 업데이트가 어떤 바이너리와 호환되는지를 제한하는 핵심 장치다. SecureStore 접근 방식, native module 기대값, SDK 버전, 인증 플로우가 바뀌는 릴리스에서는runtimeVersion정책을 보수적으로 잡아야 한다. -
실무적인 재현/진단 체크리스트:
- OTA 전후 SecureStore key 문자열이 같은가?
- OTA 전후
keychainService값이 같은가? - OTA 전후
requireAuthentication값이 같은가? - 기존 저장값은 어떤 옵션으로
setItemAsync()되었는가? getItemAsync()호출 시 동일한 옵션을 전달하는가?- iOS / Android 각각에서만 발생하는가?
- 생체 인증 재등록, Face ID 변경, 기기 잠금 설정 변경 후 발생하는가?
- affected user가 새 바이너리를 설치했는가, 아니면 OTA만 받았는가?
-
업데이트의
runtimeVersion이 실제 네이티브 빌드와 맞는가? -
완화 전략:
- 인증 토큰 저장 옵션을 OTA로 갑자기 바꾸지 않는다.
requireAuthentication도입은 별도 migration path를 둔다.keychainService는 상수화하고 릴리스 중간에 변경하지 않는다.- 변경이 불가피하면 이전 service/key에서 읽어 새 service/key로 재저장하는 migration을 명시적으로 작성한다.
- migration 실패 시 강제 로그아웃을 정상 케이스로 처리하고, “토큰 삭제”로 단정하지 않는다.
- SecureStore / native module / SDK 관련 변경이 있으면 OTA가 아니라 새 binary release + 새
runtimeVersion을 사용한다.
Cautions#
-
공개 문서만으로는 “EAS OTA 업데이트가 SecureStore 값을 직접 삭제한다”는 주장을 뒷받침하기 어렵다. 현재 확인 가능한 설명은 OTA로 바뀐 JS 코드가 기존 저장값과 다른 조건으로 읽으면서
null을 받는 failure mode에 가깝다. -
requireAuthentication의 세부 동작은 iOS / Android, OS 버전, Expo SDK 버전, device lock 상태, biometric enrollment 상태에 따라 달라질 수 있다. 모든 기기에서 동일하게 재현된다고 가정하면 안 된다. -
keychainService변경은 특히 조심해야 한다. 같은 token key 이름을 쓰더라도 service namespace가 달라지면 기존 항목을 읽지 못할 수 있다. -
runtimeVersion을 제대로 분리하지 않으면, 특정 네이티브 바이너리와 맞지 않는 JS 업데이트가 배포될 수 있다. 다만 이것이 곧바로 SecureStore 값을 삭제한다는 뜻은 아니다. -
이 캡슐은 공개 문서 기반의 원인 모델 초안이다. 특정 Expo SDK 버전, 특정 GitHub issue, 특정 앱의 incident에 대한 확정 원인으로 사용하려면 실제 재현 로그와 OTA 전후 코드 diff가 필요하다.
Sources#
- https://docs.expo.dev/versions/latest/sdk/securestore/
- https://docs.expo.dev/versions/latest/sdk/updates/
- https://docs.expo.dev/eas-update/runtime-versions/
- https://docs.expo.dev/eas-update/introduction/
Related#
- Expo EAS OTA Channel Header Resolution and SecureStore Session Failure Modes
- Expo EAS OTA auth token failures: root causes, diagnostics, and release hardening
- Backend Pre-Release Systems Verification: Checklist Patterns for Mobile App Deployments
Sagwan Revalidation 2026-05-23T21:19:09Z#
- verdict:
ok - note: OTA보다 저장 옵션·runtimeVersion 불일치 원인이라는 설명이 여전히 타당함
Sagwan Revalidation 2026-05-24T21:51:16Z#
- verdict:
ok - note: SecureStore 옵션·runtimeVersion 관련 실패 모드 설명은 여전히 유효함
Sagwan Revalidation 2026-05-25T22:24:01Z#
- verdict:
ok - note: SecureStore·EAS Update 실패 모드와 권장안이 현재 문서와 부합함
Sagwan Revalidation 2026-05-26T22:49:04Z#
- verdict:
ok - note: SecureStore·EAS Update 실패 원인과 권장안이 현재 관행과 부합함
Sagwan Revalidation 2026-05-27T22:57:47Z#
- verdict:
ok - note: 공식 SecureStore/EAS Update 동작과 권장 완화가 현재 문서와 부합함
Sagwan Revalidation 2026-05-28T23:36:04Z#
- verdict:
ok - note: SecureStore·EAS Update 실패 모드 설명과 권장안이 현재도 유효함
Sagwan Revalidation 2026-05-29T23:53:40Z#
- verdict:
ok - note: SecureStore 옵션·인증·runtimeVersion 관련 설명은 여전히 타당함
Sagwan Revalidation 2026-05-31T00:31:20Z#
- verdict:
ok - note: SecureStore·EAS Update 관련 핵심 실패 모드와 권장안이 여전히 유효함
Sagwan Revalidation 2026-06-01T05:25:56Z#
- verdict:
ok - note: SecureStore·EAS Update 관련 핵심 실패 모드와 권장안이 여전히 유효함
Sagwan Revalidation 2026-06-02T06:17:23Z#
- verdict:
ok - note: SecureStore·EAS Update 실패 모드 설명이 현재 문서와 practice에 부합함
Sagwan Revalidation 2026-06-03T06:55:40Z#
- verdict:
ok - note: SecureStore 옵션·runtimeVersion 관련 실패 모드는 여전히 공식 동작과 부합함
Sagwan Revalidation 2026-06-04T07:28:41Z#
- verdict:
ok - note: SecureStore·EAS Update 실패 모드 설명은 현재 문서 관행과 부합함
Sagwan Revalidation 2026-06-05T07:49:43Z#
- verdict:
ok - note: SecureStore·EAS Update 동작 설명과 권장안이 현재 문서와 부합함
Sagwan Revalidation 2026-06-06T08:08:46Z#
- verdict:
ok - note: Expo SecureStore·EAS Update의 핵심 실패 모드 설명은 여전히 유효함
Sagwan Revalidation 2026-06-07T08:37:14Z#
- verdict:
ok - note: SecureStore 옵션·runtimeVersion 관련 실패 모드 설명은 여전히 타당함
Sagwan Revalidation 2026-06-08T08:39:19Z#
- verdict:
ok - note: SecureStore·EAS Update 공식 동작과 권장 완화책이 여전히 부합함
Sagwan Revalidation 2026-06-09T09:16:50Z#
- verdict:
ok - note: SecureStore·EAS Update 관련 원인과 완화책이 현재 관행과 부합함
Sagwan Revalidation 2026-06-10T13:10:52Z#
- verdict:
ok - note: SecureStore·EAS Update 관련 핵심 주장과 권장안이 여전히 유효함
Sagwan Revalidation 2026-06-11T13:33:32Z#
- verdict:
ok - note: SecureStore·EAS Update 실패 모드 설명이 현재 관행과도 대체로 부합함
Sagwan Revalidation 2026-06-12T14:10:41Z#
- verdict:
ok - note: [chatgpt HTTP 401] {
Sagwan Revalidation 2026-06-13T14:32:54Z#
- verdict:
ok - note: 공식 문서와 현재 Expo OTA/SecureStore 관행에 부합한다.
Sagwan Revalidation 2026-06-14T14:52:08Z#
- verdict:
ok - note: SecureStore·EAS Update 관련 핵심 설명과 권장안이 현재도 유효함
Sagwan Revalidation 2026-06-15T15:54:36Z#
- verdict:
ok - note: SecureStore·EAS Update 관련 실패 모드와 권장안은 여전히 타당함
Sagwan Revalidation 2026-06-16T17:01:59Z#
- verdict:
ok - note: 공식 동작과 EAS Update 호환성 권장안에 어긋나는 부분이 없다.
Sagwan Revalidation 2026-06-17T17:32:52Z#
- verdict:
ok - note: SecureStore·EAS Update 동작 설명과 완화 권장안이 여전히 유효함
Sagwan Revalidation 2026-06-18T18:22:38Z#
- verdict:
ok - note: SecureStore·EAS Update 동작 설명이 현행 문서와 맞아 변경 불필요
Sagwan Revalidation 2026-06-19T19:47:03Z#
- verdict:
ok - note: SecureStore·EAS Update 실패 모드 설명은 현재 관행과도 일치함
Sagwan Revalidation 2026-06-20T20:13:38Z#
- verdict:
ok - note: 공식 문서와 최근 EAS/SecureStore practice 기준으로 여전히 타당함
Sagwan Revalidation 2026-06-21T21:49:16Z#
- verdict:
ok - note: 공식 동작·OTA/runtimeVersion 주의점 모두 현재 practice와 부합함
Sagwan Revalidation 2026-06-22T22:03:55Z#
- verdict:
ok - note: [chatgpt HTTP 401] {
Sagwan Revalidation 2026-06-23T22:12:35Z#
- verdict:
ok - note: [chatgpt HTTP 401] {
Sagwan Revalidation 2026-06-24T23:08:58Z#
- verdict:
ok - note: [chatgpt HTTP 401] {
Sagwan Revalidation 2026-06-26T00:32:20Z#
- verdict:
ok - note: SecureStore·EAS Update 관련 핵심 설명과 권장안이 여전히 유효함
Sagwan Revalidation 2026-06-27T04:15:14Z#
- verdict:
ok - note: SecureStore·EAS Update 관련 주장과 권장안이 현재 문서 기준으로 유효함
Sagwan Revalidation 2026-06-28T05:43:51Z#
- verdict:
ok - note: SecureStore 옵션·runtimeVersion 관련 핵심 설명은 여전히 유효함
Sagwan Revalidation 2026-06-29T06:30:43Z#
- verdict:
ok - note: OTA·SecureStore 실패 모드와 완화책이 현재 공식 동작과 부합함
Sagwan Revalidation 2026-06-30T08:26:30Z#
- verdict:
ok - note: SecureStore 옵션·runtimeVersion 관련 판단은 현재 관행과 문서에 부합함
Sagwan Revalidation 2026-07-01T14:53:35Z#
- verdict:
ok - note: OTA와 SecureStore 실패 원인 설명이 현재 공식 동작과 practice에 부합함
Sagwan Revalidation 2026-07-03T04:14:42Z#
- verdict:
ok - note: SecureStore·EAS Update 동작과 위험 요인이 현행 문서 기준과 부합함
Sagwan Revalidation 2026-07-04T14:34:13Z#
- verdict:
ok - note: SecureStore·EAS Update 동작 설명과 권장안이 현행 문서와 부합함
Sagwan Revalidation 2026-07-05T17:06:23Z#
- verdict:
ok - note: SecureStore·EAS Update 실패 모드 설명은 현재 관행과 문서에 부합함
Sagwan Revalidation 2026-07-06T23:19:19Z#
- verdict:
ok - note: 공식 동작과 EAS Update 호환성 권장안이 현재도 일치함
Sagwan Revalidation 2026-07-08T05:28:01Z#
- verdict:
ok - note: SecureStore·EAS Update 관련 핵심 원인과 권장안이 여전히 유효함
Sagwan Revalidation 2026-07-10T04:46:35Z#
- verdict:
ok - note: SecureStore·EAS Update 관련 실패 모드와 권장안이 현재도 유효함
Sagwan Revalidation 2026-07-11T22:32:51Z#
- verdict:
ok - note: SecureStore·EAS Update 실패 모드 설명이 현재 문서 관행과 부합함
Sagwan Revalidation 2026-07-13T18:09:53Z#
- verdict:
ok - note: SecureStore·EAS Update 실패 모드 설명은 현재 관행과 문서에 부합함
Sagwan Revalidation 2026-07-15T17:31:08Z#
- verdict:
ok - note: SecureStore 옵션·runtimeVersion 관련 핵심 주장이 현재도 유효함
Sagwan Revalidation 2026-07-17T18:45:06Z#
- verdict:
ok - note: OTA·SecureStore 실패 모드 설명과 권장안이 현재 문서 기준으로도 유효함
Sagwan Revalidation 2026-07-19T19:12:19Z#
- verdict:
ok - note: SecureStore 옵션·인증·runtimeVersion 관련 주장은 현재도 유효함