@explorins/pers-sdk-react-native 2.1.18 → 2.1.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +250 -121
- package/dist/index.js.map +1 -1
- package/dist/providers/PersSDKProvider.d.ts.map +1 -1
- package/dist/providers/PersSDKProvider.js +7 -0
- package/dist/providers/react-native-auth-provider.d.ts +1 -1
- package/dist/providers/react-native-auth-provider.d.ts.map +1 -1
- package/dist/providers/react-native-auth-provider.js +42 -9
- package/package.json +182 -182
- package/src/providers/PersSDKProvider.tsx +8 -0
- package/src/providers/react-native-auth-provider.ts +42 -12
package/dist/index.js
CHANGED
|
@@ -9588,7 +9588,113 @@ class AuthTokenManager {
|
|
|
9588
9588
|
const token = await this.getRefreshToken();
|
|
9589
9589
|
return !!token;
|
|
9590
9590
|
}
|
|
9591
|
+
/**
|
|
9592
|
+
* Clears only the refresh token.
|
|
9593
|
+
* Used when DPoP keys are regenerated, invalidating the token binding.
|
|
9594
|
+
*/
|
|
9595
|
+
async clearRefreshToken() {
|
|
9596
|
+
this.cache.refreshToken = null;
|
|
9597
|
+
await this.storage.remove(AUTH_STORAGE_KEYS.REFRESH_TOKEN);
|
|
9598
|
+
}
|
|
9599
|
+
}
|
|
9600
|
+
|
|
9601
|
+
class IndexedDBTokenStorage {
|
|
9602
|
+
constructor() {
|
|
9603
|
+
this.supportsObjects = true;
|
|
9604
|
+
this.dbPromise = null;
|
|
9605
|
+
if (typeof indexedDB === 'undefined') {
|
|
9606
|
+
console.warn('IndexedDB is not available in this environment');
|
|
9607
|
+
}
|
|
9608
|
+
}
|
|
9609
|
+
getDB() {
|
|
9610
|
+
if (this.dbPromise)
|
|
9611
|
+
return this.dbPromise;
|
|
9612
|
+
this.dbPromise = new Promise((resolve, reject) => {
|
|
9613
|
+
if (typeof indexedDB === 'undefined') {
|
|
9614
|
+
return reject(new Error('IndexedDB not supported'));
|
|
9615
|
+
}
|
|
9616
|
+
const request = indexedDB.open(IndexedDBTokenStorage.DB_NAME, IndexedDBTokenStorage.DB_VERSION);
|
|
9617
|
+
request.onupgradeneeded = (event) => {
|
|
9618
|
+
const db = event.target.result;
|
|
9619
|
+
if (!db.objectStoreNames.contains(IndexedDBTokenStorage.STORE_NAME)) {
|
|
9620
|
+
db.createObjectStore(IndexedDBTokenStorage.STORE_NAME);
|
|
9621
|
+
}
|
|
9622
|
+
};
|
|
9623
|
+
request.onsuccess = (event) => {
|
|
9624
|
+
resolve(event.target.result);
|
|
9625
|
+
};
|
|
9626
|
+
request.onerror = (event) => {
|
|
9627
|
+
reject(event.target.error);
|
|
9628
|
+
};
|
|
9629
|
+
});
|
|
9630
|
+
return this.dbPromise;
|
|
9631
|
+
}
|
|
9632
|
+
async get(key) {
|
|
9633
|
+
try {
|
|
9634
|
+
const db = await this.getDB();
|
|
9635
|
+
return new Promise((resolve, reject) => {
|
|
9636
|
+
const transaction = db.transaction(IndexedDBTokenStorage.STORE_NAME, 'readonly');
|
|
9637
|
+
const store = transaction.objectStore(IndexedDBTokenStorage.STORE_NAME);
|
|
9638
|
+
const request = store.get(key);
|
|
9639
|
+
request.onsuccess = () => resolve(request.result || null);
|
|
9640
|
+
request.onerror = () => reject(request.error);
|
|
9641
|
+
});
|
|
9642
|
+
}
|
|
9643
|
+
catch (e) {
|
|
9644
|
+
console.warn('[IndexedDBTokenStorage] Failed to get key', key, e);
|
|
9645
|
+
return null;
|
|
9646
|
+
}
|
|
9647
|
+
}
|
|
9648
|
+
async set(key, value) {
|
|
9649
|
+
try {
|
|
9650
|
+
const db = await this.getDB();
|
|
9651
|
+
return new Promise((resolve, reject) => {
|
|
9652
|
+
const transaction = db.transaction(IndexedDBTokenStorage.STORE_NAME, 'readwrite');
|
|
9653
|
+
const store = transaction.objectStore(IndexedDBTokenStorage.STORE_NAME);
|
|
9654
|
+
const request = store.put(value, key);
|
|
9655
|
+
request.onsuccess = () => resolve();
|
|
9656
|
+
request.onerror = () => reject(request.error);
|
|
9657
|
+
});
|
|
9658
|
+
}
|
|
9659
|
+
catch (e) {
|
|
9660
|
+
console.error('[IndexedDBTokenStorage] Failed to set key', key, e);
|
|
9661
|
+
throw e;
|
|
9662
|
+
}
|
|
9663
|
+
}
|
|
9664
|
+
async remove(key) {
|
|
9665
|
+
try {
|
|
9666
|
+
const db = await this.getDB();
|
|
9667
|
+
return new Promise((resolve, reject) => {
|
|
9668
|
+
const transaction = db.transaction(IndexedDBTokenStorage.STORE_NAME, 'readwrite');
|
|
9669
|
+
const store = transaction.objectStore(IndexedDBTokenStorage.STORE_NAME);
|
|
9670
|
+
const request = store.delete(key);
|
|
9671
|
+
request.onsuccess = () => resolve();
|
|
9672
|
+
request.onerror = () => reject(request.error);
|
|
9673
|
+
});
|
|
9674
|
+
}
|
|
9675
|
+
catch (e) {
|
|
9676
|
+
console.warn('[IndexedDBTokenStorage] Failed to remove key', key, e);
|
|
9677
|
+
}
|
|
9678
|
+
}
|
|
9679
|
+
async clear() {
|
|
9680
|
+
try {
|
|
9681
|
+
const db = await this.getDB();
|
|
9682
|
+
return new Promise((resolve, reject) => {
|
|
9683
|
+
const transaction = db.transaction(IndexedDBTokenStorage.STORE_NAME, 'readwrite');
|
|
9684
|
+
const store = transaction.objectStore(IndexedDBTokenStorage.STORE_NAME);
|
|
9685
|
+
const request = store.clear();
|
|
9686
|
+
request.onsuccess = () => resolve();
|
|
9687
|
+
request.onerror = () => reject(request.error);
|
|
9688
|
+
});
|
|
9689
|
+
}
|
|
9690
|
+
catch (e) {
|
|
9691
|
+
console.warn('[IndexedDBTokenStorage] Failed to clear storage', e);
|
|
9692
|
+
}
|
|
9693
|
+
}
|
|
9591
9694
|
}
|
|
9695
|
+
IndexedDBTokenStorage.DB_NAME = 'pers-sdk-storage';
|
|
9696
|
+
IndexedDBTokenStorage.STORE_NAME = 'auth-tokens';
|
|
9697
|
+
IndexedDBTokenStorage.DB_VERSION = 1;
|
|
9592
9698
|
|
|
9593
9699
|
class WebDPoPCryptoProvider {
|
|
9594
9700
|
get crypto() {
|
|
@@ -9724,13 +9830,30 @@ const DPOP_STORAGE_KEYS = {
|
|
|
9724
9830
|
PRIVATE: 'pers_dpop_private_key'
|
|
9725
9831
|
};
|
|
9726
9832
|
class DPoPManager {
|
|
9727
|
-
constructor(storage, cryptoProvider) {
|
|
9833
|
+
constructor(storage, cryptoProvider, callbacks) {
|
|
9728
9834
|
this.storage = storage;
|
|
9729
9835
|
this.memoryKeyPair = null;
|
|
9730
9836
|
this.cryptoProvider = cryptoProvider || new WebDPoPCryptoProvider();
|
|
9837
|
+
this.callbacks = callbacks || {};
|
|
9838
|
+
}
|
|
9839
|
+
/**
|
|
9840
|
+
* Checks if DPoP keys exist in storage without generating new ones.
|
|
9841
|
+
* Useful for detecting if a key regeneration would be needed.
|
|
9842
|
+
*/
|
|
9843
|
+
async hasStoredKeys() {
|
|
9844
|
+
if (this.memoryKeyPair)
|
|
9845
|
+
return true;
|
|
9846
|
+
const storedPublic = await this.storage.get(DPOP_STORAGE_KEYS.PUBLIC);
|
|
9847
|
+
const storedPrivate = await this.storage.get(DPOP_STORAGE_KEYS.PRIVATE);
|
|
9848
|
+
return !!(storedPublic && storedPrivate);
|
|
9731
9849
|
}
|
|
9732
9850
|
/**
|
|
9733
9851
|
* Ensures a DPoP key pair exists, loading from storage or generating new one.
|
|
9852
|
+
*
|
|
9853
|
+
* IMPORTANT: If keys are regenerated (not loaded from storage), this will
|
|
9854
|
+
* invalidate any refresh tokens bound to the old keys. The onKeysRegenerated
|
|
9855
|
+
* callback should clear the refresh token to prevent "DPoP proof does not
|
|
9856
|
+
* match refresh token binding" errors.
|
|
9734
9857
|
*/
|
|
9735
9858
|
async ensureKeyPair() {
|
|
9736
9859
|
if (this.memoryKeyPair)
|
|
@@ -9746,10 +9869,12 @@ class DPoPManager {
|
|
|
9746
9869
|
return this.memoryKeyPair;
|
|
9747
9870
|
}
|
|
9748
9871
|
catch (e) {
|
|
9749
|
-
console.warn('Corrupted DPoP keys in storage, regenerating.');
|
|
9872
|
+
console.warn('[DPoPManager] Corrupted DPoP keys in storage, regenerating.');
|
|
9750
9873
|
}
|
|
9751
9874
|
}
|
|
9752
9875
|
// Generate new key pair
|
|
9876
|
+
// IMPORTANT: This invalidates any existing refresh tokens bound to the old keys
|
|
9877
|
+
console.info('[DPoPManager] Generating new DPoP key pair');
|
|
9753
9878
|
// Adaptation: If storage supports raw objects (like IndexedDB or Native Keychain),
|
|
9754
9879
|
// we can generate Non-Extractable keys for maximum security.
|
|
9755
9880
|
// If storage is text-only (LocalStorage), we must use Extractable keys to serialize them.
|
|
@@ -9761,6 +9886,15 @@ class DPoPManager {
|
|
|
9761
9886
|
await this.storage.set(DPOP_STORAGE_KEYS.PUBLIC, keyPair.publicKey);
|
|
9762
9887
|
await this.storage.set(DPOP_STORAGE_KEYS.PRIVATE, keyPair.privateKey);
|
|
9763
9888
|
this.memoryKeyPair = keyPair;
|
|
9889
|
+
// Notify that keys were regenerated - refresh tokens bound to old keys are now invalid
|
|
9890
|
+
if (this.callbacks.onKeysRegenerated) {
|
|
9891
|
+
try {
|
|
9892
|
+
this.callbacks.onKeysRegenerated();
|
|
9893
|
+
}
|
|
9894
|
+
catch (e) {
|
|
9895
|
+
console.warn('[DPoPManager] onKeysRegenerated callback failed:', e);
|
|
9896
|
+
}
|
|
9897
|
+
}
|
|
9764
9898
|
return keyPair;
|
|
9765
9899
|
}
|
|
9766
9900
|
/**
|
|
@@ -9814,16 +9948,61 @@ class DefaultAuthProvider {
|
|
|
9814
9948
|
this.config = config;
|
|
9815
9949
|
this.authTypeCache = null;
|
|
9816
9950
|
this.authType = config.authType || exports.AccountOwnerType.USER;
|
|
9951
|
+
// Determine if DPoP can be enabled:
|
|
9952
|
+
// 1. Custom crypto provider is supplied (e.g., React Native), OR
|
|
9953
|
+
// 2. IndexedDB is available for browser CryptoKey persistence
|
|
9954
|
+
const hasCustomCryptoProvider = !!config.dpop?.cryptoProvider;
|
|
9955
|
+
const hasIndexedDB = this.canEnableDPoP();
|
|
9956
|
+
const canUseDPoP = hasCustomCryptoProvider || hasIndexedDB;
|
|
9957
|
+
this.dpopEnabled = !!(config.dpop?.enabled && canUseDPoP);
|
|
9958
|
+
// Debug logging for DPoP configuration
|
|
9959
|
+
console.log('[DefaultAuthProvider] DPoP config:', {
|
|
9960
|
+
requestedEnabled: config.dpop?.enabled ?? false,
|
|
9961
|
+
hasCustomCryptoProvider,
|
|
9962
|
+
hasIndexedDB,
|
|
9963
|
+
canUseDPoP,
|
|
9964
|
+
finalEnabled: this.dpopEnabled,
|
|
9965
|
+
cryptoProviderType: config.dpop?.cryptoProvider?.constructor?.name || 'none'
|
|
9966
|
+
});
|
|
9967
|
+
if (config.dpop?.enabled && !canUseDPoP) {
|
|
9968
|
+
console.warn('[DefaultAuthProvider] DPoP disabled: IndexedDB not available and no custom crypto provider supplied. CryptoKey persistence requires IndexedDB or a custom provider.');
|
|
9969
|
+
}
|
|
9817
9970
|
const storage = config.storage || this.createStorage();
|
|
9818
9971
|
this.tokenManager = new AuthTokenManager(storage);
|
|
9819
|
-
if (
|
|
9820
|
-
this.dpopManager = new DPoPManager(storage, config.dpop
|
|
9972
|
+
if (this.dpopEnabled) {
|
|
9973
|
+
this.dpopManager = new DPoPManager(storage, config.dpop?.cryptoProvider, {
|
|
9974
|
+
// When DPoP keys are regenerated (corrupted/missing), the refresh token
|
|
9975
|
+
// bound to the old keys becomes invalid. Clear it to prevent
|
|
9976
|
+
// "DPoP proof does not match refresh token binding" errors.
|
|
9977
|
+
onKeysRegenerated: () => {
|
|
9978
|
+
console.info('[DefaultAuthProvider] DPoP keys regenerated, clearing invalid refresh token');
|
|
9979
|
+
this.tokenManager.clearRefreshToken().catch(err => {
|
|
9980
|
+
console.warn('[DefaultAuthProvider] Failed to clear refresh token:', err);
|
|
9981
|
+
});
|
|
9982
|
+
}
|
|
9983
|
+
});
|
|
9821
9984
|
}
|
|
9822
9985
|
}
|
|
9986
|
+
canEnableDPoP() {
|
|
9987
|
+
// DPoP requires IndexedDB for proper CryptoKey persistence
|
|
9988
|
+
// LocalStorage cannot serialize CryptoKey objects correctly
|
|
9989
|
+
return typeof window !== 'undefined' && typeof indexedDB !== 'undefined';
|
|
9990
|
+
}
|
|
9823
9991
|
createStorage() {
|
|
9824
|
-
|
|
9825
|
-
|
|
9826
|
-
|
|
9992
|
+
// Server-side: use memory storage
|
|
9993
|
+
if (typeof window === 'undefined') {
|
|
9994
|
+
return new MemoryTokenStorage();
|
|
9995
|
+
}
|
|
9996
|
+
// Browser with DPoP enabled: use IndexedDB for CryptoKey persistence
|
|
9997
|
+
if (this.dpopEnabled) {
|
|
9998
|
+
return new IndexedDBTokenStorage();
|
|
9999
|
+
}
|
|
10000
|
+
// Browser without DPoP: use LocalStorage
|
|
10001
|
+
if (typeof localStorage !== 'undefined') {
|
|
10002
|
+
return new LocalStorageTokenStorage();
|
|
10003
|
+
}
|
|
10004
|
+
// Fallback
|
|
10005
|
+
return new MemoryTokenStorage();
|
|
9827
10006
|
}
|
|
9828
10007
|
getToken() {
|
|
9829
10008
|
return this.tokenManager.getAccessToken();
|
|
@@ -9905,10 +10084,9 @@ class DefaultAuthProvider {
|
|
|
9905
10084
|
async hasValidToken() {
|
|
9906
10085
|
return this.tokenManager.hasAccessToken();
|
|
9907
10086
|
}
|
|
9908
|
-
async setAuthType(
|
|
9909
|
-
//
|
|
9910
|
-
//
|
|
9911
|
-
// This method exists to satisfy the ExtendedTokenStorageProvider interface
|
|
10087
|
+
async setAuthType(_authType) {
|
|
10088
|
+
// No-op: authType is derived from JWT payload via getAuthType()
|
|
10089
|
+
// @see getAuthType() - reads accountType directly from JWT
|
|
9912
10090
|
}
|
|
9913
10091
|
async getAuthType() {
|
|
9914
10092
|
// Read from JWT instead of separate storage for single source of truth
|
|
@@ -9949,12 +10127,14 @@ class DefaultAuthProvider {
|
|
|
9949
10127
|
* Exported for consumers who need version info.
|
|
9950
10128
|
* Used internally for X-SDK-Version header.
|
|
9951
10129
|
*
|
|
10130
|
+
* Version is injected at build time via @rollup/plugin-replace
|
|
10131
|
+
*
|
|
9952
10132
|
* @module @explorins/pers-sdk/core
|
|
9953
10133
|
*/
|
|
9954
10134
|
/** SDK package name */
|
|
9955
|
-
const SDK_NAME =
|
|
9956
|
-
/** SDK version -
|
|
9957
|
-
const SDK_VERSION =
|
|
10135
|
+
const SDK_NAME = "@explorins/pers-sdk";
|
|
10136
|
+
/** SDK version - injected from package.json at build time */
|
|
10137
|
+
const SDK_VERSION = "2.1.27";
|
|
9958
10138
|
/** Full SDK identifier for headers */
|
|
9959
10139
|
const SDK_USER_AGENT = `${SDK_NAME}/${SDK_VERSION}`;
|
|
9960
10140
|
|
|
@@ -10884,7 +11064,14 @@ class AuthManager {
|
|
|
10884
11064
|
*/
|
|
10885
11065
|
async loginWithRawData(rawUserData) {
|
|
10886
11066
|
const authService = this.apiClient.getAuthService();
|
|
10887
|
-
|
|
11067
|
+
const result = await authService.loginUserWithRawData(rawUserData);
|
|
11068
|
+
this.events?.emitSuccess({
|
|
11069
|
+
domain: 'authentication',
|
|
11070
|
+
type: 'login_success',
|
|
11071
|
+
userMessage: 'Successfully logged in',
|
|
11072
|
+
details: { user: result.user }
|
|
11073
|
+
});
|
|
11074
|
+
return result;
|
|
10888
11075
|
}
|
|
10889
11076
|
/**
|
|
10890
11077
|
* Get current authenticated user
|
|
@@ -18859,104 +19046,6 @@ function createPersSDK(httpClient, config) {
|
|
|
18859
19046
|
return new PersSDK(httpClient, config);
|
|
18860
19047
|
}
|
|
18861
19048
|
|
|
18862
|
-
class IndexedDBTokenStorage {
|
|
18863
|
-
constructor() {
|
|
18864
|
-
this.supportsObjects = true;
|
|
18865
|
-
this.dbPromise = null;
|
|
18866
|
-
if (typeof indexedDB === 'undefined') {
|
|
18867
|
-
console.warn('IndexedDB is not available in this environment');
|
|
18868
|
-
}
|
|
18869
|
-
}
|
|
18870
|
-
getDB() {
|
|
18871
|
-
if (this.dbPromise)
|
|
18872
|
-
return this.dbPromise;
|
|
18873
|
-
this.dbPromise = new Promise((resolve, reject) => {
|
|
18874
|
-
if (typeof indexedDB === 'undefined') {
|
|
18875
|
-
return reject(new Error('IndexedDB not supported'));
|
|
18876
|
-
}
|
|
18877
|
-
const request = indexedDB.open(IndexedDBTokenStorage.DB_NAME, IndexedDBTokenStorage.DB_VERSION);
|
|
18878
|
-
request.onupgradeneeded = (event) => {
|
|
18879
|
-
const db = event.target.result;
|
|
18880
|
-
if (!db.objectStoreNames.contains(IndexedDBTokenStorage.STORE_NAME)) {
|
|
18881
|
-
db.createObjectStore(IndexedDBTokenStorage.STORE_NAME);
|
|
18882
|
-
}
|
|
18883
|
-
};
|
|
18884
|
-
request.onsuccess = (event) => {
|
|
18885
|
-
resolve(event.target.result);
|
|
18886
|
-
};
|
|
18887
|
-
request.onerror = (event) => {
|
|
18888
|
-
reject(event.target.error);
|
|
18889
|
-
};
|
|
18890
|
-
});
|
|
18891
|
-
return this.dbPromise;
|
|
18892
|
-
}
|
|
18893
|
-
async get(key) {
|
|
18894
|
-
try {
|
|
18895
|
-
const db = await this.getDB();
|
|
18896
|
-
return new Promise((resolve, reject) => {
|
|
18897
|
-
const transaction = db.transaction(IndexedDBTokenStorage.STORE_NAME, 'readonly');
|
|
18898
|
-
const store = transaction.objectStore(IndexedDBTokenStorage.STORE_NAME);
|
|
18899
|
-
const request = store.get(key);
|
|
18900
|
-
request.onsuccess = () => resolve(request.result || null);
|
|
18901
|
-
request.onerror = () => reject(request.error);
|
|
18902
|
-
});
|
|
18903
|
-
}
|
|
18904
|
-
catch (e) {
|
|
18905
|
-
console.warn('[IndexedDBTokenStorage] Failed to get key', key, e);
|
|
18906
|
-
return null;
|
|
18907
|
-
}
|
|
18908
|
-
}
|
|
18909
|
-
async set(key, value) {
|
|
18910
|
-
try {
|
|
18911
|
-
const db = await this.getDB();
|
|
18912
|
-
return new Promise((resolve, reject) => {
|
|
18913
|
-
const transaction = db.transaction(IndexedDBTokenStorage.STORE_NAME, 'readwrite');
|
|
18914
|
-
const store = transaction.objectStore(IndexedDBTokenStorage.STORE_NAME);
|
|
18915
|
-
const request = store.put(value, key);
|
|
18916
|
-
request.onsuccess = () => resolve();
|
|
18917
|
-
request.onerror = () => reject(request.error);
|
|
18918
|
-
});
|
|
18919
|
-
}
|
|
18920
|
-
catch (e) {
|
|
18921
|
-
console.error('[IndexedDBTokenStorage] Failed to set key', key, e);
|
|
18922
|
-
throw e;
|
|
18923
|
-
}
|
|
18924
|
-
}
|
|
18925
|
-
async remove(key) {
|
|
18926
|
-
try {
|
|
18927
|
-
const db = await this.getDB();
|
|
18928
|
-
return new Promise((resolve, reject) => {
|
|
18929
|
-
const transaction = db.transaction(IndexedDBTokenStorage.STORE_NAME, 'readwrite');
|
|
18930
|
-
const store = transaction.objectStore(IndexedDBTokenStorage.STORE_NAME);
|
|
18931
|
-
const request = store.delete(key);
|
|
18932
|
-
request.onsuccess = () => resolve();
|
|
18933
|
-
request.onerror = () => reject(request.error);
|
|
18934
|
-
});
|
|
18935
|
-
}
|
|
18936
|
-
catch (e) {
|
|
18937
|
-
console.warn('[IndexedDBTokenStorage] Failed to remove key', key, e);
|
|
18938
|
-
}
|
|
18939
|
-
}
|
|
18940
|
-
async clear() {
|
|
18941
|
-
try {
|
|
18942
|
-
const db = await this.getDB();
|
|
18943
|
-
return new Promise((resolve, reject) => {
|
|
18944
|
-
const transaction = db.transaction(IndexedDBTokenStorage.STORE_NAME, 'readwrite');
|
|
18945
|
-
const store = transaction.objectStore(IndexedDBTokenStorage.STORE_NAME);
|
|
18946
|
-
const request = store.clear();
|
|
18947
|
-
request.onsuccess = () => resolve();
|
|
18948
|
-
request.onerror = () => reject(request.error);
|
|
18949
|
-
});
|
|
18950
|
-
}
|
|
18951
|
-
catch (e) {
|
|
18952
|
-
console.warn('[IndexedDBTokenStorage] Failed to clear storage', e);
|
|
18953
|
-
}
|
|
18954
|
-
}
|
|
18955
|
-
}
|
|
18956
|
-
IndexedDBTokenStorage.DB_NAME = 'pers-sdk-storage';
|
|
18957
|
-
IndexedDBTokenStorage.STORE_NAME = 'auth-tokens';
|
|
18958
|
-
IndexedDBTokenStorage.DB_VERSION = 1;
|
|
18959
|
-
|
|
18960
19049
|
/**
|
|
18961
19050
|
* Environment Detection Utility
|
|
18962
19051
|
* Detects runtime environment for platform-specific behaviors
|
|
@@ -19282,11 +19371,19 @@ class ReactNativeSecureStorage {
|
|
|
19282
19371
|
* React Native Unified Auth Provider
|
|
19283
19372
|
*
|
|
19284
19373
|
* Creates a platform-specific auth provider that automatically selects the appropriate storage:
|
|
19285
|
-
* - Web: Uses
|
|
19374
|
+
* - Web: Uses IndexedDBTokenStorage for DPoP (CryptoKey persistence) or LocalStorage
|
|
19286
19375
|
* - Mobile: Uses AsyncStorage-based storage
|
|
19287
19376
|
*/
|
|
19288
19377
|
// Use React Native's built-in platform detection
|
|
19289
19378
|
const isWebPlatform = reactNative.Platform.OS === 'web';
|
|
19379
|
+
/**
|
|
19380
|
+
* Check if IndexedDB is available (web environments only)
|
|
19381
|
+
* Uses globalThis to avoid TypeScript errors in React Native context
|
|
19382
|
+
*/
|
|
19383
|
+
function hasIndexedDB() {
|
|
19384
|
+
return typeof globalThis !== 'undefined' &&
|
|
19385
|
+
typeof globalThis.indexedDB !== 'undefined';
|
|
19386
|
+
}
|
|
19290
19387
|
/**
|
|
19291
19388
|
* Create a React Native auth provider with platform-appropriate storage
|
|
19292
19389
|
*
|
|
@@ -19304,18 +19401,43 @@ function createReactNativeAuthProvider(projectKey, config = {}) {
|
|
|
19304
19401
|
}
|
|
19305
19402
|
const { keyPrefix = `pers_${projectKey.slice(0, 8)}_`, debug = false, customStorage, authType = exports.AccountOwnerType.USER, dpop } = config;
|
|
19306
19403
|
// Platform-specific storage selection
|
|
19307
|
-
|
|
19308
|
-
|
|
19309
|
-
|
|
19404
|
+
// Web with DPoP: Use IndexedDB for CryptoKey persistence
|
|
19405
|
+
// Web without DPoP or no IndexedDB: Use LocalStorage
|
|
19406
|
+
// Mobile: Use ReactNativeSecureStorage
|
|
19407
|
+
let tokenStorage;
|
|
19408
|
+
if (customStorage) {
|
|
19409
|
+
tokenStorage = customStorage;
|
|
19410
|
+
}
|
|
19411
|
+
else if (isWebPlatform) {
|
|
19412
|
+
// On web, prefer IndexedDB when DPoP is enabled for proper CryptoKey persistence
|
|
19413
|
+
const dpopEnabled = dpop?.enabled ?? true;
|
|
19414
|
+
if (dpopEnabled && hasIndexedDB()) {
|
|
19415
|
+
tokenStorage = new IndexedDBTokenStorage();
|
|
19416
|
+
}
|
|
19417
|
+
else {
|
|
19418
|
+
if (dpopEnabled && !hasIndexedDB()) {
|
|
19419
|
+
console.warn('[ReactNativeAuthProvider] DPoP requested but IndexedDB not available. Falling back to LocalStorage (DPoP will be disabled by DefaultAuthProvider).');
|
|
19420
|
+
}
|
|
19421
|
+
tokenStorage = new LocalStorageTokenStorage();
|
|
19422
|
+
}
|
|
19423
|
+
}
|
|
19424
|
+
else {
|
|
19425
|
+
tokenStorage = new ReactNativeSecureStorage(keyPrefix);
|
|
19426
|
+
}
|
|
19310
19427
|
// Prepare DPoP config ensuring enabled is boolean (default true)
|
|
19311
19428
|
const dpopConfig = dpop ? {
|
|
19312
19429
|
enabled: dpop.enabled ?? true,
|
|
19313
19430
|
cryptoProvider: dpop.cryptoProvider
|
|
19314
19431
|
} : undefined;
|
|
19315
|
-
//
|
|
19316
|
-
|
|
19317
|
-
|
|
19318
|
-
|
|
19432
|
+
// Always log DPoP config for debugging (critical for mobile auth)
|
|
19433
|
+
console.log('[ReactNativeAuthProvider] Config:', {
|
|
19434
|
+
platform: reactNative.Platform.OS,
|
|
19435
|
+
isWebPlatform,
|
|
19436
|
+
dpopEnabled: dpopConfig?.enabled ?? false,
|
|
19437
|
+
hasCryptoProvider: !!dpopConfig?.cryptoProvider,
|
|
19438
|
+
cryptoProviderType: dpopConfig?.cryptoProvider?.constructor?.name || 'none',
|
|
19439
|
+
storageType: tokenStorage.constructor.name
|
|
19440
|
+
});
|
|
19319
19441
|
// Return DefaultAuthProvider configured with platform-appropriate storage
|
|
19320
19442
|
return new DefaultAuthProvider({
|
|
19321
19443
|
authType,
|
|
@@ -19642,6 +19764,13 @@ const PersSDKProvider = ({ children, config }) => {
|
|
|
19642
19764
|
if (reactNative.Platform.OS !== 'web' && isDpopEnabled && !dpopSettings.cryptoProvider) {
|
|
19643
19765
|
dpopSettings.cryptoProvider = new ReactNativeDPoPProvider();
|
|
19644
19766
|
}
|
|
19767
|
+
// Log DPoP settings before creating auth provider
|
|
19768
|
+
console.log('[PersSDKProvider] DPoP settings:', {
|
|
19769
|
+
platform: reactNative.Platform.OS,
|
|
19770
|
+
isDpopEnabled,
|
|
19771
|
+
hasCryptoProvider: !!dpopSettings.cryptoProvider,
|
|
19772
|
+
cryptoProviderType: dpopSettings.cryptoProvider?.constructor?.name || 'none'
|
|
19773
|
+
});
|
|
19645
19774
|
// Create platform-aware auth provider if not provided
|
|
19646
19775
|
let authProvider;
|
|
19647
19776
|
if (config.authProvider) {
|