@witsauth/react-native-client 1.0.0 → 1.0.1

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.
@@ -1,4 +1,4 @@
1
- import { OAuth2NativeConfig, TokenInfo } from '../models/types';
1
+ import { AuthorizeOptions, LogoutOptions, OAuth2NativeConfig, TokenInfo, UserProfile } from '../models/types';
2
2
  import { NativeTokenStorage } from './storage';
3
3
  export declare class AuthClient {
4
4
  private config;
@@ -14,12 +14,12 @@ export declare class AuthClient {
14
14
  /**
15
15
  * Builds the OAuth 2.0 + PKCE authorization URL and persists `code_verifier`, `state`, and `nonce`.
16
16
  */
17
- buildAuthorizationUrl(): Promise<string>;
17
+ buildAuthorizationUrl(options?: AuthorizeOptions): Promise<string>;
18
18
  /**
19
19
  * Launches the system authentication browser (`ASWebAuthenticationSession` on iOS / Chrome Custom Tabs on Android),
20
20
  * intercepts the deep-link callback (`redirectUri`), validates `state`, and exchanges `code` + `code_verifier` for tokens.
21
21
  */
22
- authorize(): Promise<TokenInfo>;
22
+ authorize(options?: AuthorizeOptions): Promise<TokenInfo>;
23
23
  /**
24
24
  * Parses a redirect callback URL (`myapp://auth/callback?code=...&state=...`) and exchanges the code for tokens.
25
25
  */
@@ -28,6 +28,8 @@ export declare class AuthClient {
28
28
  refreshAccessToken(): Promise<TokenInfo>;
29
29
  private saveTokenInfo;
30
30
  getAccessToken(): string | null;
31
+ getIdToken(): string | null;
32
+ getUserProfile<T extends UserProfile = UserProfile>(): T | null;
31
33
  getRefreshToken(): string | null;
32
34
  getExpiresAt(): number | null;
33
35
  isAuthenticated(): boolean;
@@ -39,6 +41,8 @@ export declare class AuthClient {
39
41
  navigateToAccountManagement(): Promise<void>;
40
42
  /**
41
43
  * Clears tokens from secure storage and revokes both refresh_token and access_token at `revokeEndpoint`.
44
+ * If `options.clearBrowserSession` is true and `logoutEndpoint` + `openAuthSession` are configured,
45
+ * launches the system browser to terminate the WitsAuth web session cookie.
42
46
  */
43
- logout(): Promise<void>;
47
+ logout(options?: LogoutOptions): Promise<void>;
44
48
  }
@@ -9,6 +9,8 @@
9
9
  */
10
10
  export declare function sha256Bytes(asciiOrUtf8: string): Uint8Array;
11
11
  export declare function base64UrlEncode(bytes: Uint8Array): string;
12
+ export declare function getRandomBytes(length: number): Uint8Array;
13
+ export declare function decodeJwtPayload<T = Record<string, unknown>>(token: string | null | undefined): T | null;
12
14
  export declare function generateRandomString(length?: number): string;
13
15
  export declare function generateCodeVerifier(): string;
14
16
  export declare function generateState(): string;
@@ -22,6 +22,8 @@ export declare class NativeTokenStorage {
22
22
  export declare function createMemoryStorageAdapter(): OAuth2AsyncStorage;
23
23
  /**
24
24
  * Helper to create a storage adapter backed by `expo-secure-store`.
25
+ * Automatically splits values exceeding 2000 bytes across indexed chunk keys
26
+ * to prevent Expo SecureStore's 2048-byte limit errors on large JWTs.
25
27
  * Pass the imported `SecureStore` module from `expo-secure-store`.
26
28
  */
27
29
  export declare function createExpoSecureStoreAdapter(secureStoreModule: {
package/dist/index.es.js CHANGED
@@ -122,21 +122,56 @@ function f(e) {
122
122
  function p(e) {
123
123
  let t = new Uint8Array(e), n = typeof globalThis < "u" ? globalThis : void 0;
124
124
  if (n?.crypto && typeof n.crypto.getRandomValues == "function") return n.crypto.getRandomValues(t), t;
125
- for (let n = 0; n < e; n++) t[n] = Math.floor(Math.random() * 256);
126
- return t;
125
+ try {
126
+ let r = typeof n?.require == "function" ? n.require : void 0;
127
+ if (r) {
128
+ let n = r("expo-crypto");
129
+ if (n && typeof n.getRandomValues == "function") return n.getRandomValues(t), t;
130
+ if (n && typeof n.getRandomBytes == "function") {
131
+ let r = n.getRandomBytes(e);
132
+ return t.set(r.subarray(0, e)), t;
133
+ }
134
+ }
135
+ } catch {}
136
+ throw Error("Cryptographically secure random number generator (CSPRNG) is unavailable. Please install and import \"react-native-get-random-values\" or \"expo-crypto\".");
137
+ }
138
+ function m(e) {
139
+ let t = e.replace(/-/g, "+").replace(/_/g, "/"), n = t + "=".repeat((4 - t.length % 4) % 4);
140
+ if (typeof atob == "function") {
141
+ let e = atob(n), t = new Uint8Array(e.length);
142
+ for (let n = 0; n < e.length; n++) t[n] = e.charCodeAt(n);
143
+ if (typeof TextDecoder < "u") return new TextDecoder().decode(t);
144
+ let r = "";
145
+ for (let e = 0; e < t.length; e++) r += String.fromCharCode(t[e]);
146
+ return decodeURIComponent(escape(r));
147
+ }
148
+ let r = typeof globalThis < "u" ? globalThis : void 0;
149
+ if (r?.Buffer) return r.Buffer.from(n, "base64").toString("utf8");
150
+ throw Error("Unable to decode base64url string.");
151
+ }
152
+ function h(e) {
153
+ if (!e || typeof e != "string") return null;
154
+ let t = e.split(".");
155
+ if (t.length < 2) return null;
156
+ try {
157
+ let e = m(t[1]);
158
+ return JSON.parse(e);
159
+ } catch {
160
+ return null;
161
+ }
127
162
  }
128
- function m(e = 64) {
163
+ function g(e = 64) {
129
164
  let t = p(e), n = "";
130
165
  for (let r = 0; r < e; r++) n += "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~"[t[r] % 66];
131
166
  return n;
132
167
  }
133
- function h() {
134
- return m(64);
168
+ function _() {
169
+ return g(64);
135
170
  }
136
- function g() {
137
- return m(32);
171
+ function v() {
172
+ return g(32);
138
173
  }
139
- async function _(e) {
174
+ async function y(e) {
140
175
  let t = typeof globalThis < "u" ? globalThis : void 0;
141
176
  if (t?.crypto?.subtle && typeof t.crypto.subtle.digest == "function") try {
142
177
  let n = u(e), r = await t.crypto.subtle.digest("SHA-256", n);
@@ -145,17 +180,17 @@ async function _(e) {
145
180
  return f(d(e));
146
181
  }
147
182
  // src/core/storage.ts
148
- var v = Object.values(o), y = class {
183
+ var b = Object.values(o), x = class {
149
184
  backend;
150
185
  cache = /* @__PURE__ */ new Map();
151
186
  hydrated = !1;
152
187
  hydratePromise = null;
153
188
  constructor(e) {
154
- this.backend = e || b();
189
+ this.backend = e || S();
155
190
  }
156
191
  async hydrate() {
157
192
  if (!this.hydrated) return this.hydratePromise ||= (async () => {
158
- await Promise.all(v.map(async (e) => {
193
+ await Promise.all(b.map(async (e) => {
159
194
  try {
160
195
  let t = await this.backend.getItem(e);
161
196
  t != null && this.cache.set(e, t);
@@ -197,7 +232,7 @@ var v = Object.values(o), y = class {
197
232
  ]);
198
233
  }
199
234
  };
200
- function b() {
235
+ function S() {
201
236
  let e = /* @__PURE__ */ new Map();
202
237
  return {
203
238
  getItem: async (t) => e.get(t) ?? null,
@@ -209,14 +244,51 @@ function b() {
209
244
  }
210
245
  };
211
246
  }
212
- function x(e) {
247
+ var C = 2e3, w = "__witsauth_chunked__:";
248
+ function T(e) {
249
+ let t = async (t) => {
250
+ try {
251
+ let n = await e.getItemAsync(t);
252
+ if (n && n.startsWith(w)) {
253
+ let r = parseInt(n.slice(21), 10);
254
+ if (Number.isFinite(r) && r > 0) {
255
+ let n = [];
256
+ for (let i = 0; i < r; i++) n.push(e.deleteItemAsync(`${t}__chunk_${i}`));
257
+ await Promise.all(n);
258
+ }
259
+ }
260
+ } catch {}
261
+ };
213
262
  return {
214
- getItem: (t) => e.getItemAsync(t),
215
- setItem: (t, n) => e.setItemAsync(t, n),
216
- removeItem: (t) => e.deleteItemAsync(t)
263
+ getItem: async (t) => {
264
+ let n = await e.getItemAsync(t);
265
+ if (!n) return null;
266
+ if (n.startsWith(w)) {
267
+ let r = parseInt(n.slice(21), 10);
268
+ if (!Number.isFinite(r) || r <= 0) return null;
269
+ let i = [];
270
+ for (let n = 0; n < r; n++) i.push(e.getItemAsync(`${t}__chunk_${n}`));
271
+ let a = await Promise.all(i);
272
+ return a.some((e) => e == null) ? null : a.join("");
273
+ }
274
+ return n;
275
+ },
276
+ setItem: async (n, r) => {
277
+ if (r.length <= C) {
278
+ await t(n), await e.setItemAsync(n, r);
279
+ return;
280
+ }
281
+ await t(n);
282
+ let i = [];
283
+ for (let e = 0; e < r.length; e += C) i.push(r.slice(e, e + C));
284
+ await Promise.all(i.map((t, r) => e.setItemAsync(`${n}__chunk_${r}`, t))), await e.setItemAsync(n, `${w}${i.length}`);
285
+ },
286
+ removeItem: async (n) => {
287
+ await t(n), await e.deleteItemAsync(n);
288
+ }
217
289
  };
218
290
  }
219
- function S(e, t = "com.witsauth.tokens") {
291
+ function E(e, t = "com.witsauth.tokens") {
220
292
  return {
221
293
  getItem: async (n) => {
222
294
  let r = await e.getGenericPassword({ service: `${t}.${n}` });
@@ -231,7 +303,7 @@ function S(e, t = "com.witsauth.tokens") {
231
303
  };
232
304
  }
233
305
  // src/core/browser.ts
234
- function C(e) {
306
+ function D(e) {
235
307
  return async (t, n) => {
236
308
  let r = await e.openAuthSessionAsync(t, n);
237
309
  return r.type === "success" && r.url ? {
@@ -240,7 +312,7 @@ function C(e) {
240
312
  } : r.type === "cancel" ? { type: "cancel" } : { type: "dismiss" };
241
313
  };
242
314
  }
243
- function w(e) {
315
+ function O(e) {
244
316
  return async (t, n) => {
245
317
  if (!await e.isAvailable()) throw Error("InAppBrowser is not available on this device.");
246
318
  let r = await e.openAuth(t, n, {
@@ -255,7 +327,7 @@ function w(e) {
255
327
  } : r.type === "cancel" ? { type: "cancel" } : { type: "dismiss" };
256
328
  };
257
329
  }
258
- function T(e) {
330
+ function k(e) {
259
331
  let t = e.indexOf("?");
260
332
  if (t === -1) return {
261
333
  code: null,
@@ -272,12 +344,12 @@ function T(e) {
272
344
  };
273
345
  }
274
346
  // src/core/AuthClient.ts
275
- var E = class {
347
+ var A = class {
276
348
  config;
277
349
  storage;
278
350
  refreshPromise = null;
279
351
  constructor(e, t) {
280
- this.config = e, this.storage = t || new y(e.storage);
352
+ this.config = e, this.storage = t || new x(e.storage);
281
353
  }
282
354
  async initialize() {
283
355
  await this.storage.hydrate();
@@ -292,33 +364,34 @@ var E = class {
292
364
  }, r = n[this.config.logLevel || "warn"] || 0, i = n[e] || 0;
293
365
  i > 0 && r >= i && console[e](...t);
294
366
  }
295
- async buildAuthorizationUrl() {
367
+ async buildAuthorizationUrl(e) {
296
368
  await this.storage.hydrate();
297
- let e = h(), t = await _(e), n = g(), r = this.config.nonce || g();
298
- await this.storage.setItem(o.CODE_VERIFIER, e), await this.storage.setItem(o.STATE, n), await this.storage.setItem(o.NONCE, r);
299
- let i = new URLSearchParams({
369
+ let t = _(), n = await y(t), r = v(), i = this.config.nonce || v();
370
+ await this.storage.setItem(o.CODE_VERIFIER, t), await this.storage.setItem(o.STATE, r), await this.storage.setItem(o.NONCE, i);
371
+ let a = new URLSearchParams({
300
372
  client_id: this.config.clientId,
301
373
  redirect_uri: this.config.redirectUri,
302
374
  response_type: this.config.responseType || "code",
303
375
  code_challenge_method: this.config.codeChallengeMethod || "S256",
304
- code_challenge: t,
305
- state: n,
306
- nonce: r
376
+ code_challenge: n,
377
+ state: r,
378
+ nonce: i
307
379
  });
308
380
  if (this.config.theme) {
309
381
  let e = typeof this.config.theme == "function" ? this.config.theme() : this.config.theme;
310
- e && i.append("theme", e);
382
+ e && a.append("theme", e);
311
383
  }
312
- return this.config.scope && i.append("scope", this.config.scope), this.config.audience && i.append("audience", this.config.audience), `${this.config.authorizationEndpoint}?${i.toString()}`;
384
+ let s = e?.scope ?? this.config.scope, c = e?.audience ?? this.config.audience;
385
+ return s && a.append("scope", s), c && a.append("audience", c), e?.prompt && a.append("prompt", e.prompt), `${this.config.authorizationEndpoint}?${a.toString()}`;
313
386
  }
314
- async authorize() {
387
+ async authorize(e) {
315
388
  if (!this.config.openAuthSession) throw Error("No openAuthSession launcher configured. Pass createExpoWebBrowserLauncher(WebBrowser) or createInAppBrowserLauncher(InAppBrowser) in OAuth2NativeConfig.");
316
- let e = await this.buildAuthorizationUrl(), t = await this.config.openAuthSession(e, this.config.redirectUri);
317
- if (t.type !== "success" || !t.url) throw await this.storage.clearTemporary(), Error(`Authentication ${t.type}`);
318
- return this.handleCallbackUrl(t.url);
389
+ let t = await this.buildAuthorizationUrl(e), n = await this.config.openAuthSession(t, this.config.redirectUri);
390
+ if (n.type !== "success" || !n.url) throw await this.storage.clearTemporary(), Error(`Authentication ${n.type}`);
391
+ return this.handleCallbackUrl(n.url);
319
392
  }
320
393
  async handleCallbackUrl(e) {
321
- let { code: t, state: n, error: r, errorDescription: i } = T(e);
394
+ let { code: t, state: n, error: r, errorDescription: i } = k(e);
322
395
  if (r) throw await this.storage.clearTemporary(), Error(i ? `${r}: ${i}` : r);
323
396
  if (!t || !n) throw await this.storage.clearTemporary(), Error("Callback URL is missing required code or state parameters.");
324
397
  return this.exchangeCodeForTokens(t, n);
@@ -403,6 +476,12 @@ var E = class {
403
476
  getAccessToken() {
404
477
  return this.storage.getItemSync(o.ACCESS_TOKEN);
405
478
  }
479
+ getIdToken() {
480
+ return this.storage.getItemSync(o.ID_TOKEN);
481
+ }
482
+ getUserProfile() {
483
+ return h(this.getIdToken() || this.getAccessToken());
484
+ }
406
485
  getRefreshToken() {
407
486
  return this.storage.getItemSync(o.REFRESH_TOKEN);
408
487
  }
@@ -436,24 +515,24 @@ var E = class {
436
515
  let i = `${t}/account?ticket=${encodeURIComponent(r)}&return_to=${encodeURIComponent(this.config.redirectUri)}`;
437
516
  await this.config.openAuthSession(i, this.config.redirectUri);
438
517
  }
439
- async logout() {
518
+ async logout(e) {
440
519
  await this.storage.hydrate();
441
- let e = this.getAccessToken(), t = await this.storage.getItem(o.REFRESH_TOKEN);
520
+ let t = this.getAccessToken(), n = await this.storage.getItem(o.REFRESH_TOKEN);
442
521
  if (await this.storage.clearTokens(), await this.storage.clearTemporary(), this.config.revokeEndpoint) {
443
- let n = [...t ? [{
444
- token: t,
522
+ let e = [...n ? [{
523
+ token: n,
445
524
  token_type_hint: "refresh_token"
446
- }] : [], ...e ? [{
447
- token: e,
525
+ }] : [], ...t ? [{
526
+ token: t,
448
527
  token_type_hint: "access_token"
449
528
  }] : []];
450
- for (let e of n) try {
529
+ for (let t of e) try {
451
530
  await fetch(this.config.revokeEndpoint, {
452
531
  method: "POST",
453
532
  headers: { "Content-Type": "application/x-www-form-urlencoded" },
454
533
  body: new URLSearchParams({
455
- token: e.token,
456
- token_type_hint: e.token_type_hint,
534
+ token: t.token,
535
+ token_type_hint: t.token_type_hint,
457
536
  client_id: this.config.clientId
458
537
  }).toString()
459
538
  });
@@ -461,38 +540,49 @@ var E = class {
461
540
  this.log("error", "Failed to revoke token during logout", e);
462
541
  }
463
542
  }
543
+ if (e?.clearBrowserSession && this.config.logoutEndpoint && this.config.openAuthSession) {
544
+ let e = new URLSearchParams({
545
+ client_id: this.config.clientId,
546
+ redirect_uri: this.config.redirectUri
547
+ }), t = this.config.logoutEndpoint.includes("?") ? "&" : "?", n = `${this.config.logoutEndpoint}${t}${e.toString()}`;
548
+ try {
549
+ await this.config.openAuthSession(n, this.config.redirectUri);
550
+ } catch (e) {
551
+ this.log("warn", "Browser logout session dismissed or failed", e);
552
+ }
553
+ }
464
554
  }
465
- }, D = e(null), O = ({ config: e, client: n, children: o, onLoginSuccess: s, onLoginError: c, subscribeAppState: l }) => {
555
+ }, j = e(null), M = ({ config: e, client: n, children: o, onLoginSuccess: s, onLoginError: c, subscribeAppState: l }) => {
466
556
  let [u] = i(() => {
467
557
  if (n) return n;
468
- if (e) return new E(e);
558
+ if (e) return new A(e);
469
559
  throw Error("AuthProvider requires either a `client` or `config` prop.");
470
- }), [d, f] = i(!1), [p, m] = i(null), [h, g] = i(!0), [_, v] = i(null), y = t(async () => {
471
- if (await u.initialize(), u.isAuthenticated()) f(!0), m(u.getAccessToken());
560
+ }), [d, f] = i(!1), [p, m] = i(null), [h, g] = i(null), [_, v] = i(null), [y, b] = i(!0), [x, S] = i(null), C = t(async () => {
561
+ if (await u.initialize(), u.isAuthenticated()) f(!0), m(u.getAccessToken()), g(u.getIdToken()), v(u.getUserProfile());
472
562
  else {
473
563
  if (u.getRefreshToken()) try {
474
564
  let e = await u.refreshAccessToken();
475
- f(!0), m(e.accessToken);
565
+ f(!0), m(e.accessToken), g(u.getIdToken()), v(u.getUserProfile());
476
566
  return;
477
567
  } catch {
478
- f(!1), m(null);
568
+ f(!1), m(null), g(null), v(null);
479
569
  return;
480
570
  }
481
- f(!1), m(null);
571
+ f(!1), m(null), g(null), v(null);
482
572
  }
483
573
  }, [u]);
484
574
  r(() => {
485
575
  let e = !0;
486
576
  return (async () => {
487
577
  try {
488
- await y();
578
+ await C();
489
579
  } finally {
490
- e && g(!1);
580
+ e && b(!1);
491
581
  }
492
582
  })(), () => {
493
583
  e = !1;
494
584
  };
495
- }, [y]), r(() => {
585
+ }, [C]), r(() => {
496
586
  if (!d) return;
497
587
  let e, t = () => {
498
588
  let n = u.getExpiresAt();
@@ -501,15 +591,15 @@ var E = class {
501
591
  e = setTimeout(async () => {
502
592
  try {
503
593
  let e = await u.refreshAccessToken();
504
- m(e.accessToken), f(!0), t();
594
+ m(e.accessToken), g(u.getIdToken()), v(u.getUserProfile()), f(!0), t();
505
595
  } catch (n) {
506
- u.log("error", "Background token refresh failed:", n), u.getAccessToken() ? e = setTimeout(t, 3e4) : (f(!1), m(null));
596
+ u.log("error", "Background token refresh failed:", n), u.getAccessToken() ? e = setTimeout(t, 3e4) : (f(!1), m(null), g(null), v(null));
507
597
  }
508
598
  }, Math.max(0, r));
509
599
  };
510
600
  t();
511
601
  let n = l ? l((e) => {
512
- e === "active" && y().catch(() => {});
602
+ e === "active" && C().catch(() => {});
513
603
  }) : void 0;
514
604
  return () => {
515
605
  e && clearTimeout(e), n && n();
@@ -518,64 +608,66 @@ var E = class {
518
608
  d,
519
609
  u,
520
610
  l,
521
- y
611
+ C
522
612
  ]);
523
- let b = t(async () => {
524
- g(!0), v(null);
613
+ let w = t(async (e) => {
614
+ b(!0), S(null);
525
615
  try {
526
- let e = await u.authorize();
527
- m(e.accessToken), f(!0), s?.();
616
+ let t = await u.authorize(e);
617
+ m(t.accessToken), g(u.getIdToken()), v(u.getUserProfile()), f(!0), s?.();
528
618
  } catch (e) {
529
619
  let t = e instanceof Error ? e : /* @__PURE__ */ Error("Authentication failed");
530
- v(t), c?.(t);
620
+ S(t), c?.(t);
531
621
  } finally {
532
- g(!1);
622
+ b(!1);
533
623
  }
534
624
  }, [
535
625
  u,
536
626
  s,
537
627
  c
538
- ]), x = t(async () => {
539
- g(!0);
628
+ ]), T = t(async (e) => {
629
+ b(!0);
540
630
  try {
541
- await u.logout(), f(!1), m(null);
631
+ await u.logout(e), f(!1), m(null), g(null), v(null);
542
632
  } catch (e) {
543
- v(e instanceof Error ? e : /* @__PURE__ */ Error("Logout failed"));
633
+ S(e instanceof Error ? e : /* @__PURE__ */ Error("Logout failed"));
544
634
  } finally {
545
- g(!1);
635
+ b(!1);
546
636
  }
547
- }, [u]), S = t(async () => {
637
+ }, [u]), E = t(async () => {
548
638
  if (await u.initialize(), u.isAuthenticated()) return u.getAccessToken();
549
639
  try {
550
640
  let e = await u.refreshAccessToken();
551
- return m(e.accessToken), f(!0), e.accessToken;
641
+ return m(e.accessToken), g(u.getIdToken()), v(u.getUserProfile()), f(!0), e.accessToken;
552
642
  } catch {
553
- return f(!1), m(null), null;
643
+ return f(!1), m(null), g(null), v(null), null;
554
644
  }
555
- }, [u]), C = t(async () => {
556
- await u.navigateToAccountManagement(), await y();
557
- }, [u, y]);
558
- return /* @__PURE__ */ a(D.Provider, {
645
+ }, [u]), D = t(async () => {
646
+ await u.navigateToAccountManagement(), await C();
647
+ }, [u, C]);
648
+ return /* @__PURE__ */ a(j.Provider, {
559
649
  value: {
560
650
  isAuthenticated: d,
561
- isLoading: h,
651
+ isLoading: y,
562
652
  accessToken: p,
563
- error: _,
564
- login: b,
565
- logout: x,
566
- getToken: S,
567
- navigateToAccountManagement: C,
653
+ idToken: h,
654
+ user: _,
655
+ error: x,
656
+ login: w,
657
+ logout: T,
658
+ getToken: E,
659
+ navigateToAccountManagement: D,
568
660
  authClient: u
569
661
  },
570
662
  children: o
571
663
  });
572
- }, k = () => {
573
- let e = n(D);
664
+ }, N = () => {
665
+ let e = n(j);
574
666
  if (!e) throw Error("useAuth must be used within an AuthProvider");
575
667
  return e;
576
668
  };
577
669
  // src/axios/interceptor.ts
578
- function A(e, t, n = {}) {
670
+ function P(e, t, n = {}) {
579
671
  let r = !1, i = [], a = (e, t = null) => {
580
672
  i.forEach((n) => {
581
673
  e ? n.reject(e) : n.resolve(t);
@@ -616,4 +708,4 @@ function A(e, t, n = {}) {
616
708
  e.interceptors.request.eject(s), e.interceptors.response.eject(c);
617
709
  };
618
710
  }
619
- export { E as AuthClient, O as AuthProvider, y as NativeTokenStorage, o as STORAGE_KEYS, f as base64UrlEncode, _ as createCodeChallenge, x as createExpoSecureStoreAdapter, C as createExpoWebBrowserLauncher, w as createInAppBrowserLauncher, S as createKeychainStorageAdapter, b as createMemoryStorageAdapter, h as generateCodeVerifier, m as generateRandomString, g as generateState, T as parseCallbackUrl, A as setupAxiosInterceptors, d as sha256Bytes, k as useAuth };
711
+ export { A as AuthClient, M as AuthProvider, x as NativeTokenStorage, o as STORAGE_KEYS, f as base64UrlEncode, y as createCodeChallenge, T as createExpoSecureStoreAdapter, D as createExpoWebBrowserLauncher, O as createInAppBrowserLauncher, E as createKeychainStorageAdapter, S as createMemoryStorageAdapter, h as decodeJwtPayload, _ as generateCodeVerifier, g as generateRandomString, v as generateState, p as getRandomBytes, k as parseCallbackUrl, P as setupAxiosInterceptors, d as sha256Bytes, N as useAuth };
package/dist/index.umd.js CHANGED
@@ -1 +1 @@
1
- (function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports,require("react"),require("react/jsx-runtime")):typeof define==`function`&&define.amd?define([`exports`,`react`,`react/jsx-runtime`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e.WitsAuthReactNativeClient={},e.React,e.jsxRuntime))})(this,function(e,t,n){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var r=Object.create,i=Object.defineProperty,a=Object.getOwnPropertyDescriptor,o=Object.getOwnPropertyNames,s=Object.getPrototypeOf,c=Object.prototype.hasOwnProperty,l=(e,t,n,r)=>{if(t&&typeof t==`object`||typeof t==`function`)for(var s=o(t),l=0,u=s.length,d;l<u;l++)d=s[l],!c.call(e,d)&&d!==n&&i(e,d,{get:(e=>t[e]).bind(null,d),enumerable:!(r=a(t,d))||r.enumerable});return e};t=((e,t,n)=>(n=e==null?{}:r(s(e)),l(i(n,`default`,{value:e,enumerable:!0}),e)))(t,1);var u={ACCESS_TOKEN:`witsauth_access_token`,REFRESH_TOKEN:`witsauth_refresh_token`,TOKEN_EXPIRES_AT:`witsauth_expires_at`,TOKEN_TYPE:`witsauth_token_type`,SCOPE:`witsauth_scope`,ID_TOKEN:`witsauth_id_token`,CODE_VERIFIER:`witsauth_code_verifier`,STATE:`witsauth_state`,NONCE:`witsauth_nonce`},d=`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_`,f=new Uint32Array([1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298]);function p(e,t){return t>>>e|t<<32-e}function m(e){if(typeof TextEncoder<`u`)return new TextEncoder().encode(e);let t=[];for(let n=0;n<e.length;n++){let r=e.charCodeAt(n);r<128?t.push(r):r<2048?t.push(192|r>>6,128|r&63):r<55296||r>=57344?t.push(224|r>>12,128|r>>6&63,128|r&63):(n++,r=65536+((r&1023)<<10|e.charCodeAt(n)&1023),t.push(240|r>>18,128|r>>12&63,128|r>>6&63,128|r&63))}return new Uint8Array(t)}function h(e){let t=m(e),n=t.length*8,r=t.length+9+63>>6<<6,i=new Uint8Array(r);i.set(t),i[t.length]=128;let a=new DataView(i.buffer);a.setUint32(r-8,Math.floor(n/4294967296),!1),a.setUint32(r-4,n>>>0,!1);let o=1779033703,s=3144134277,c=1013904242,l=2773480762,u=1359893119,d=2600822924,h=528734635,g=1541459225,_=new Uint32Array(64);for(let e=0;e<r;e+=64){for(let t=0;t<16;t++)_[t]=a.getUint32(e+t*4,!1);for(let e=16;e<64;e++){let t=p(7,_[e-15])^p(18,_[e-15])^_[e-15]>>>3,n=p(17,_[e-2])^p(19,_[e-2])^_[e-2]>>>10;_[e]=_[e-16]+t+_[e-7]+n>>>0}let t=o,n=s,r=c,i=l,m=u,v=d,y=h,b=g;for(let e=0;e<64;e++){let a=p(6,m)^p(11,m)^p(25,m),o=m&v^~m&y,s=b+a+o+f[e]+_[e]>>>0,c=(p(2,t)^p(13,t)^p(22,t))+(t&n^t&r^n&r)>>>0;b=y,y=v,v=m,m=i+s>>>0,i=r,r=n,n=t,t=s+c>>>0}o=o+t>>>0,s=s+n>>>0,c=c+r>>>0,l=l+i>>>0,u=u+m>>>0,d=d+v>>>0,h=h+y>>>0,g=g+b>>>0}let v=new Uint8Array(32),y=new DataView(v.buffer);return y.setUint32(0,o,!1),y.setUint32(4,s,!1),y.setUint32(8,c,!1),y.setUint32(12,l,!1),y.setUint32(16,u,!1),y.setUint32(20,d,!1),y.setUint32(24,h,!1),y.setUint32(28,g,!1),v}function g(e){let t=``,n=e.length;for(let r=0;r<n;r+=3){let i=e[r],a=r+1<n?e[r+1]:0,o=r+2<n?e[r+2]:0;t+=d[i>>2],t+=d[(i&3)<<4|a>>4],r+1<n&&(t+=d[(a&15)<<2|o>>6]),r+2<n&&(t+=d[o&63])}return t}function _(e){let t=new Uint8Array(e),n=typeof globalThis<`u`?globalThis:void 0;if(n?.crypto&&typeof n.crypto.getRandomValues==`function`)return n.crypto.getRandomValues(t),t;for(let n=0;n<e;n++)t[n]=Math.floor(Math.random()*256);return t}function v(e=64){let t=_(e),n=``;for(let r=0;r<e;r++)n+=`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~`[t[r]%66];return n}function y(){return v(64)}function b(){return v(32)}async function x(e){let t=typeof globalThis<`u`?globalThis:void 0;if(t?.crypto?.subtle&&typeof t.crypto.subtle.digest==`function`)try{let n=m(e),r=await t.crypto.subtle.digest(`SHA-256`,n);return g(new Uint8Array(r))}catch{}return g(h(e))}var S=Object.values(u),C=class{backend;cache=new Map;hydrated=!1;hydratePromise=null;constructor(e){this.backend=e||w()}async hydrate(){if(!this.hydrated)return this.hydratePromise||=(async()=>{await Promise.all(S.map(async e=>{try{let t=await this.backend.getItem(e);t!=null&&this.cache.set(e,t)}catch{}})),this.hydrated=!0})().finally(()=>{this.hydratePromise=null}),this.hydratePromise}getItemSync(e){return this.cache.get(e)??null}async getItem(e){if(this.cache.has(e))return this.cache.get(e);let t=await this.backend.getItem(e);return t==null?null:(this.cache.set(e,t),t)}async setItem(e,t){this.cache.set(e,t),await this.backend.setItem(e,t)}async removeItem(e){this.cache.delete(e),await this.backend.removeItem(e)}async clearTemporary(){await Promise.all([this.removeItem(u.CODE_VERIFIER),this.removeItem(u.STATE),this.removeItem(u.NONCE)])}async clearTokens(){await Promise.all([this.removeItem(u.ACCESS_TOKEN),this.removeItem(u.REFRESH_TOKEN),this.removeItem(u.TOKEN_EXPIRES_AT),this.removeItem(u.TOKEN_TYPE),this.removeItem(u.SCOPE),this.removeItem(u.ID_TOKEN)])}};function w(){let e=new Map;return{getItem:async t=>e.get(t)??null,setItem:async(t,n)=>{e.set(t,n)},removeItem:async t=>{e.delete(t)}}}function T(e){return{getItem:t=>e.getItemAsync(t),setItem:(t,n)=>e.setItemAsync(t,n),removeItem:t=>e.deleteItemAsync(t)}}function E(e,t=`com.witsauth.tokens`){return{getItem:async n=>{let r=await e.getGenericPassword({service:`${t}.${n}`});return r?r.password:null},setItem:async(n,r)=>{await e.setGenericPassword(n,r,{service:`${t}.${n}`})},removeItem:async n=>{await e.resetGenericPassword({service:`${t}.${n}`})}}}function D(e){return async(t,n)=>{let r=await e.openAuthSessionAsync(t,n);return r.type===`success`&&r.url?{type:`success`,url:r.url}:r.type===`cancel`?{type:`cancel`}:{type:`dismiss`}}}function O(e){return async(t,n)=>{if(!await e.isAvailable())throw Error(`InAppBrowser is not available on this device.`);let r=await e.openAuth(t,n,{ephemeralWebSession:!1,showTitle:!1,enableUrlBarHiding:!0,enableDefaultShare:!1});return r.type===`success`&&r.url?{type:`success`,url:r.url}:r.type===`cancel`?{type:`cancel`}:{type:`dismiss`}}}function k(e){let t=e.indexOf(`?`);if(t===-1)return{code:null,state:null,error:null,errorDescription:null};let n=e.indexOf(`#`,t),r=n===-1?e.slice(t+1):e.slice(t+1,n),i=new URLSearchParams(r);return{code:i.get(`code`),state:i.get(`state`),error:i.get(`error`),errorDescription:i.get(`error_description`)}}var A=class{config;storage;refreshPromise=null;constructor(e,t){this.config=e,this.storage=t||new C(e.storage)}async initialize(){await this.storage.hydrate()}log(e,...t){let n={none:0,error:1,warn:2,info:3,debug:4},r=n[this.config.logLevel||`warn`]||0,i=n[e]||0;i>0&&r>=i&&console[e](...t)}async buildAuthorizationUrl(){await this.storage.hydrate();let e=y(),t=await x(e),n=b(),r=this.config.nonce||b();await this.storage.setItem(u.CODE_VERIFIER,e),await this.storage.setItem(u.STATE,n),await this.storage.setItem(u.NONCE,r);let i=new URLSearchParams({client_id:this.config.clientId,redirect_uri:this.config.redirectUri,response_type:this.config.responseType||`code`,code_challenge_method:this.config.codeChallengeMethod||`S256`,code_challenge:t,state:n,nonce:r});if(this.config.theme){let e=typeof this.config.theme==`function`?this.config.theme():this.config.theme;e&&i.append(`theme`,e)}return this.config.scope&&i.append(`scope`,this.config.scope),this.config.audience&&i.append(`audience`,this.config.audience),`${this.config.authorizationEndpoint}?${i.toString()}`}async authorize(){if(!this.config.openAuthSession)throw Error(`No openAuthSession launcher configured. Pass createExpoWebBrowserLauncher(WebBrowser) or createInAppBrowserLauncher(InAppBrowser) in OAuth2NativeConfig.`);let e=await this.buildAuthorizationUrl(),t=await this.config.openAuthSession(e,this.config.redirectUri);if(t.type!==`success`||!t.url)throw await this.storage.clearTemporary(),Error(`Authentication ${t.type}`);return this.handleCallbackUrl(t.url)}async handleCallbackUrl(e){let{code:t,state:n,error:r,errorDescription:i}=k(e);if(r)throw await this.storage.clearTemporary(),Error(i?`${r}: ${i}`:r);if(!t||!n)throw await this.storage.clearTemporary(),Error(`Callback URL is missing required code or state parameters.`);return this.exchangeCodeForTokens(t,n)}async exchangeCodeForTokens(e,t){await this.storage.hydrate();let n=await this.storage.getItem(u.STATE),r=await this.storage.getItem(u.CODE_VERIFIER);if(!n||t!==n)throw await this.storage.clearTemporary(),Error(`Invalid state parameter. Possible CSRF attack.`);if(!r)throw await this.storage.clearTemporary(),Error(`Code verifier missing from storage.`);let i=new URLSearchParams({grant_type:`authorization_code`,client_id:this.config.clientId,redirect_uri:this.config.redirectUri,code:e,code_verifier:r}),a=await fetch(this.config.tokenEndpoint,{method:`POST`,headers:{"Content-Type":`application/x-www-form-urlencoded`},body:i.toString()});if(!a.ok)throw Error(`Failed to exchange code for tokens`);let o=await a.json(),s={accessToken:o.access_token,refreshToken:o.refresh_token,tokenType:o.token_type||`Bearer`,expiresAt:Date.now()+o.expires_in*1e3,scope:o.scope,idToken:o.id_token};return await this.saveTokenInfo(s),await this.storage.clearTemporary(),s}async refreshAccessToken(){return this.refreshPromise||=(async()=>{await this.storage.hydrate();let e=await this.storage.getItem(u.REFRESH_TOKEN);if(!e)throw Error(`No refresh token available`);let t=new URLSearchParams({grant_type:`refresh_token`,client_id:this.config.clientId,refresh_token:e}),n;try{n=await fetch(this.config.tokenEndpoint,{method:`POST`,headers:{"Content-Type":`application/x-www-form-urlencoded`},body:t.toString()})}catch(e){throw this.log(`error`,`Token refresh network request failed:`,e),e}if(!n.ok){let e={};try{e=await n.json()}catch{try{e={error:await n.text()}}catch{e={}}}this.log(`error`,`Token refresh failed with status:`,n.status,e),(n.status===400||n.status===401)&&await this.storage.clearTokens();let t=e.error_description||e.error||n.statusText||`Failed to refresh token`;throw Error(`Failed to refresh token (${n.status}): ${t}`)}let r=await n.json(),i={accessToken:r.access_token,refreshToken:r.refresh_token||e,tokenType:r.token_type||`Bearer`,expiresAt:Date.now()+r.expires_in*1e3,scope:r.scope,idToken:r.id_token};return await this.saveTokenInfo(i),i})().finally(()=>{this.refreshPromise=null}),this.refreshPromise}async saveTokenInfo(e){await this.storage.setItem(u.ACCESS_TOKEN,e.accessToken),await this.storage.setItem(u.TOKEN_EXPIRES_AT,e.expiresAt.toString()),await this.storage.setItem(u.TOKEN_TYPE,e.tokenType),e.refreshToken&&await this.storage.setItem(u.REFRESH_TOKEN,e.refreshToken),e.scope&&await this.storage.setItem(u.SCOPE,e.scope),e.idToken&&await this.storage.setItem(u.ID_TOKEN,e.idToken)}getAccessToken(){return this.storage.getItemSync(u.ACCESS_TOKEN)}getRefreshToken(){return this.storage.getItemSync(u.REFRESH_TOKEN)}getExpiresAt(){let e=this.storage.getItemSync(u.TOKEN_EXPIRES_AT);if(!e)return null;let t=Number(e);return Number.isFinite(t)?t:null}isAuthenticated(){let e=this.getExpiresAt();return e!==null&&Date.now()<e-3e4&&!!this.getAccessToken()}async navigateToAccountManagement(){await this.storage.hydrate();let e=await this.storage.getItem(u.REFRESH_TOKEN);if(!e)throw Error(`No refresh token available to access account management.`);if(!this.config.openAuthSession)throw Error(`No openAuthSession launcher configured. Pass createExpoWebBrowserLauncher(WebBrowser) or createInAppBrowserLauncher(InAppBrowser) in OAuth2NativeConfig.`);let t=this.config.authorizationEndpoint.replace(/\/authorize\/?$/,``),n=await fetch(`${t}/account/ticket`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({refreshToken:e,clientId:this.config.clientId,redirectUri:this.config.redirectUri})});if(!n.ok)throw Error(`Failed to request account management ticket (${n.status})`);let{ticket:r}=await n.json();if(!r)throw Error(`Account management ticket missing from server response.`);let i=`${t}/account?ticket=${encodeURIComponent(r)}&return_to=${encodeURIComponent(this.config.redirectUri)}`;await this.config.openAuthSession(i,this.config.redirectUri)}async logout(){await this.storage.hydrate();let e=this.getAccessToken(),t=await this.storage.getItem(u.REFRESH_TOKEN);if(await this.storage.clearTokens(),await this.storage.clearTemporary(),this.config.revokeEndpoint){let n=[...t?[{token:t,token_type_hint:`refresh_token`}]:[],...e?[{token:e,token_type_hint:`access_token`}]:[]];for(let e of n)try{await fetch(this.config.revokeEndpoint,{method:`POST`,headers:{"Content-Type":`application/x-www-form-urlencoded`},body:new URLSearchParams({token:e.token,token_type_hint:e.token_type_hint,client_id:this.config.clientId}).toString()})}catch(e){this.log(`error`,`Failed to revoke token during logout`,e)}}}},j=(0,t.createContext)(null),M=({config:e,client:r,children:i,onLoginSuccess:a,onLoginError:o,subscribeAppState:s})=>{let[c]=(0,t.useState)(()=>{if(r)return r;if(e)return new A(e);throw Error("AuthProvider requires either a `client` or `config` prop.")}),[l,u]=(0,t.useState)(!1),[d,f]=(0,t.useState)(null),[p,m]=(0,t.useState)(!0),[h,g]=(0,t.useState)(null),_=(0,t.useCallback)(async()=>{if(await c.initialize(),c.isAuthenticated())u(!0),f(c.getAccessToken());else{if(c.getRefreshToken())try{let e=await c.refreshAccessToken();u(!0),f(e.accessToken);return}catch{u(!1),f(null);return}u(!1),f(null)}},[c]);(0,t.useEffect)(()=>{let e=!0;return(async()=>{try{await _()}finally{e&&m(!1)}})(),()=>{e=!1}},[_]),(0,t.useEffect)(()=>{if(!l)return;let e,t=()=>{let n=c.getExpiresAt();if(!n)return;let r=n-Date.now()-6e4;e=setTimeout(async()=>{try{let e=await c.refreshAccessToken();f(e.accessToken),u(!0),t()}catch(n){c.log(`error`,`Background token refresh failed:`,n),c.getAccessToken()?e=setTimeout(t,3e4):(u(!1),f(null))}},Math.max(0,r))};t();let n=s?s(e=>{e===`active`&&_().catch(()=>{})}):void 0;return()=>{e&&clearTimeout(e),n&&n()}},[l,c,s,_]);let v=(0,t.useCallback)(async()=>{m(!0),g(null);try{let e=await c.authorize();f(e.accessToken),u(!0),a?.()}catch(e){let t=e instanceof Error?e:Error(`Authentication failed`);g(t),o?.(t)}finally{m(!1)}},[c,a,o]),y=(0,t.useCallback)(async()=>{m(!0);try{await c.logout(),u(!1),f(null)}catch(e){g(e instanceof Error?e:Error(`Logout failed`))}finally{m(!1)}},[c]),b=(0,t.useCallback)(async()=>{if(await c.initialize(),c.isAuthenticated())return c.getAccessToken();try{let e=await c.refreshAccessToken();return f(e.accessToken),u(!0),e.accessToken}catch{return u(!1),f(null),null}},[c]),x=(0,t.useCallback)(async()=>{await c.navigateToAccountManagement(),await _()},[c,_]);return(0,n.jsx)(j.Provider,{value:{isAuthenticated:l,isLoading:p,accessToken:d,error:h,login:v,logout:y,getToken:b,navigateToAccountManagement:x,authClient:c},children:i})},N=()=>{let e=(0,t.useContext)(j);if(!e)throw Error(`useAuth must be used within an AuthProvider`);return e};function P(e,t,n={}){let r=!1,i=[],a=(e,t=null)=>{i.forEach(n=>{e?n.reject(e):n.resolve(t)}),i=[]},o=e=>!e||!n.excludeUrls?!1:n.excludeUrls.some(t=>typeof t==`string`?e.includes(t):t.test(e)),s=e.interceptors.request.use(async e=>{if(o(e.url))return e;await t.initialize();let n=t.getAccessToken();if(!t.isAuthenticated()&&n)try{n=(await t.refreshAccessToken()).accessToken}catch{n=null}return n&&e.headers.set(`Authorization`,`Bearer ${n}`),e},e=>Promise.reject(e)),c=e.interceptors.response.use(e=>e,async s=>{let c=s.config;if(!c||o(c.url))return Promise.reject(s);if(s.response?.status===401&&!c._retry){if(r)return new Promise((e,t)=>{i.push({resolve:e,reject:t})}).then(t=>(t&&c.headers.set(`Authorization`,`Bearer ${t}`),e(c))).catch(e=>Promise.reject(e));c._retry=!0,r=!0;try{let n=(await t.refreshAccessToken()).accessToken;return a(null,n),c.headers.set(`Authorization`,`Bearer ${n}`),e(c)}catch(e){return a(e,null),await t.logout(),n.onUnauthorized&&n.onUnauthorized(),Promise.reject(e)}finally{r=!1}}return Promise.reject(s)});return()=>{e.interceptors.request.eject(s),e.interceptors.response.eject(c)}}e.AuthClient=A,e.AuthProvider=M,e.NativeTokenStorage=C,e.STORAGE_KEYS=u,e.base64UrlEncode=g,e.createCodeChallenge=x,e.createExpoSecureStoreAdapter=T,e.createExpoWebBrowserLauncher=D,e.createInAppBrowserLauncher=O,e.createKeychainStorageAdapter=E,e.createMemoryStorageAdapter=w,e.generateCodeVerifier=y,e.generateRandomString=v,e.generateState=b,e.parseCallbackUrl=k,e.setupAxiosInterceptors=P,e.sha256Bytes=h,e.useAuth=N});
1
+ (function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports,require("react"),require("react/jsx-runtime")):typeof define==`function`&&define.amd?define([`exports`,`react`,`react/jsx-runtime`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e.WitsAuthReactNativeClient={},e.React,e.jsxRuntime))})(this,function(e,t,n){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var r=Object.create,i=Object.defineProperty,a=Object.getOwnPropertyDescriptor,o=Object.getOwnPropertyNames,s=Object.getPrototypeOf,c=Object.prototype.hasOwnProperty,l=(e,t,n,r)=>{if(t&&typeof t==`object`||typeof t==`function`)for(var s=o(t),l=0,u=s.length,d;l<u;l++)d=s[l],!c.call(e,d)&&d!==n&&i(e,d,{get:(e=>t[e]).bind(null,d),enumerable:!(r=a(t,d))||r.enumerable});return e};t=((e,t,n)=>(n=e==null?{}:r(s(e)),l(i(n,`default`,{value:e,enumerable:!0}),e)))(t,1);var u={ACCESS_TOKEN:`witsauth_access_token`,REFRESH_TOKEN:`witsauth_refresh_token`,TOKEN_EXPIRES_AT:`witsauth_expires_at`,TOKEN_TYPE:`witsauth_token_type`,SCOPE:`witsauth_scope`,ID_TOKEN:`witsauth_id_token`,CODE_VERIFIER:`witsauth_code_verifier`,STATE:`witsauth_state`,NONCE:`witsauth_nonce`},d=`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_`,f=new Uint32Array([1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298]);function p(e,t){return t>>>e|t<<32-e}function m(e){if(typeof TextEncoder<`u`)return new TextEncoder().encode(e);let t=[];for(let n=0;n<e.length;n++){let r=e.charCodeAt(n);r<128?t.push(r):r<2048?t.push(192|r>>6,128|r&63):r<55296||r>=57344?t.push(224|r>>12,128|r>>6&63,128|r&63):(n++,r=65536+((r&1023)<<10|e.charCodeAt(n)&1023),t.push(240|r>>18,128|r>>12&63,128|r>>6&63,128|r&63))}return new Uint8Array(t)}function h(e){let t=m(e),n=t.length*8,r=t.length+9+63>>6<<6,i=new Uint8Array(r);i.set(t),i[t.length]=128;let a=new DataView(i.buffer);a.setUint32(r-8,Math.floor(n/4294967296),!1),a.setUint32(r-4,n>>>0,!1);let o=1779033703,s=3144134277,c=1013904242,l=2773480762,u=1359893119,d=2600822924,h=528734635,g=1541459225,_=new Uint32Array(64);for(let e=0;e<r;e+=64){for(let t=0;t<16;t++)_[t]=a.getUint32(e+t*4,!1);for(let e=16;e<64;e++){let t=p(7,_[e-15])^p(18,_[e-15])^_[e-15]>>>3,n=p(17,_[e-2])^p(19,_[e-2])^_[e-2]>>>10;_[e]=_[e-16]+t+_[e-7]+n>>>0}let t=o,n=s,r=c,i=l,m=u,v=d,y=h,b=g;for(let e=0;e<64;e++){let a=p(6,m)^p(11,m)^p(25,m),o=m&v^~m&y,s=b+a+o+f[e]+_[e]>>>0,c=(p(2,t)^p(13,t)^p(22,t))+(t&n^t&r^n&r)>>>0;b=y,y=v,v=m,m=i+s>>>0,i=r,r=n,n=t,t=s+c>>>0}o=o+t>>>0,s=s+n>>>0,c=c+r>>>0,l=l+i>>>0,u=u+m>>>0,d=d+v>>>0,h=h+y>>>0,g=g+b>>>0}let v=new Uint8Array(32),y=new DataView(v.buffer);return y.setUint32(0,o,!1),y.setUint32(4,s,!1),y.setUint32(8,c,!1),y.setUint32(12,l,!1),y.setUint32(16,u,!1),y.setUint32(20,d,!1),y.setUint32(24,h,!1),y.setUint32(28,g,!1),v}function g(e){let t=``,n=e.length;for(let r=0;r<n;r+=3){let i=e[r],a=r+1<n?e[r+1]:0,o=r+2<n?e[r+2]:0;t+=d[i>>2],t+=d[(i&3)<<4|a>>4],r+1<n&&(t+=d[(a&15)<<2|o>>6]),r+2<n&&(t+=d[o&63])}return t}function _(e){let t=new Uint8Array(e),n=typeof globalThis<`u`?globalThis:void 0;if(n?.crypto&&typeof n.crypto.getRandomValues==`function`)return n.crypto.getRandomValues(t),t;try{let r=typeof n?.require==`function`?n.require:void 0;if(r){let n=r(`expo-crypto`);if(n&&typeof n.getRandomValues==`function`)return n.getRandomValues(t),t;if(n&&typeof n.getRandomBytes==`function`){let r=n.getRandomBytes(e);return t.set(r.subarray(0,e)),t}}}catch{}throw Error(`Cryptographically secure random number generator (CSPRNG) is unavailable. Please install and import "react-native-get-random-values" or "expo-crypto".`)}function v(e){let t=e.replace(/-/g,`+`).replace(/_/g,`/`),n=t+`=`.repeat((4-t.length%4)%4);if(typeof atob==`function`){let e=atob(n),t=new Uint8Array(e.length);for(let n=0;n<e.length;n++)t[n]=e.charCodeAt(n);if(typeof TextDecoder<`u`)return new TextDecoder().decode(t);let r=``;for(let e=0;e<t.length;e++)r+=String.fromCharCode(t[e]);return decodeURIComponent(escape(r))}let r=typeof globalThis<`u`?globalThis:void 0;if(r?.Buffer)return r.Buffer.from(n,`base64`).toString(`utf8`);throw Error(`Unable to decode base64url string.`)}function y(e){if(!e||typeof e!=`string`)return null;let t=e.split(`.`);if(t.length<2)return null;try{let e=v(t[1]);return JSON.parse(e)}catch{return null}}function b(e=64){let t=_(e),n=``;for(let r=0;r<e;r++)n+=`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~`[t[r]%66];return n}function x(){return b(64)}function S(){return b(32)}async function C(e){let t=typeof globalThis<`u`?globalThis:void 0;if(t?.crypto?.subtle&&typeof t.crypto.subtle.digest==`function`)try{let n=m(e),r=await t.crypto.subtle.digest(`SHA-256`,n);return g(new Uint8Array(r))}catch{}return g(h(e))}var w=Object.values(u),T=class{backend;cache=new Map;hydrated=!1;hydratePromise=null;constructor(e){this.backend=e||E()}async hydrate(){if(!this.hydrated)return this.hydratePromise||=(async()=>{await Promise.all(w.map(async e=>{try{let t=await this.backend.getItem(e);t!=null&&this.cache.set(e,t)}catch{}})),this.hydrated=!0})().finally(()=>{this.hydratePromise=null}),this.hydratePromise}getItemSync(e){return this.cache.get(e)??null}async getItem(e){if(this.cache.has(e))return this.cache.get(e);let t=await this.backend.getItem(e);return t==null?null:(this.cache.set(e,t),t)}async setItem(e,t){this.cache.set(e,t),await this.backend.setItem(e,t)}async removeItem(e){this.cache.delete(e),await this.backend.removeItem(e)}async clearTemporary(){await Promise.all([this.removeItem(u.CODE_VERIFIER),this.removeItem(u.STATE),this.removeItem(u.NONCE)])}async clearTokens(){await Promise.all([this.removeItem(u.ACCESS_TOKEN),this.removeItem(u.REFRESH_TOKEN),this.removeItem(u.TOKEN_EXPIRES_AT),this.removeItem(u.TOKEN_TYPE),this.removeItem(u.SCOPE),this.removeItem(u.ID_TOKEN)])}};function E(){let e=new Map;return{getItem:async t=>e.get(t)??null,setItem:async(t,n)=>{e.set(t,n)},removeItem:async t=>{e.delete(t)}}}var D=2e3,O=`__witsauth_chunked__:`;function k(e){let t=async t=>{try{let n=await e.getItemAsync(t);if(n&&n.startsWith(O)){let r=parseInt(n.slice(21),10);if(Number.isFinite(r)&&r>0){let n=[];for(let i=0;i<r;i++)n.push(e.deleteItemAsync(`${t}__chunk_${i}`));await Promise.all(n)}}}catch{}};return{getItem:async t=>{let n=await e.getItemAsync(t);if(!n)return null;if(n.startsWith(O)){let r=parseInt(n.slice(21),10);if(!Number.isFinite(r)||r<=0)return null;let i=[];for(let n=0;n<r;n++)i.push(e.getItemAsync(`${t}__chunk_${n}`));let a=await Promise.all(i);return a.some(e=>e==null)?null:a.join(``)}return n},setItem:async(n,r)=>{if(r.length<=D){await t(n),await e.setItemAsync(n,r);return}await t(n);let i=[];for(let e=0;e<r.length;e+=D)i.push(r.slice(e,e+D));await Promise.all(i.map((t,r)=>e.setItemAsync(`${n}__chunk_${r}`,t))),await e.setItemAsync(n,`${O}${i.length}`)},removeItem:async n=>{await t(n),await e.deleteItemAsync(n)}}}function A(e,t=`com.witsauth.tokens`){return{getItem:async n=>{let r=await e.getGenericPassword({service:`${t}.${n}`});return r?r.password:null},setItem:async(n,r)=>{await e.setGenericPassword(n,r,{service:`${t}.${n}`})},removeItem:async n=>{await e.resetGenericPassword({service:`${t}.${n}`})}}}function j(e){return async(t,n)=>{let r=await e.openAuthSessionAsync(t,n);return r.type===`success`&&r.url?{type:`success`,url:r.url}:r.type===`cancel`?{type:`cancel`}:{type:`dismiss`}}}function M(e){return async(t,n)=>{if(!await e.isAvailable())throw Error(`InAppBrowser is not available on this device.`);let r=await e.openAuth(t,n,{ephemeralWebSession:!1,showTitle:!1,enableUrlBarHiding:!0,enableDefaultShare:!1});return r.type===`success`&&r.url?{type:`success`,url:r.url}:r.type===`cancel`?{type:`cancel`}:{type:`dismiss`}}}function N(e){let t=e.indexOf(`?`);if(t===-1)return{code:null,state:null,error:null,errorDescription:null};let n=e.indexOf(`#`,t),r=n===-1?e.slice(t+1):e.slice(t+1,n),i=new URLSearchParams(r);return{code:i.get(`code`),state:i.get(`state`),error:i.get(`error`),errorDescription:i.get(`error_description`)}}var P=class{config;storage;refreshPromise=null;constructor(e,t){this.config=e,this.storage=t||new T(e.storage)}async initialize(){await this.storage.hydrate()}log(e,...t){let n={none:0,error:1,warn:2,info:3,debug:4},r=n[this.config.logLevel||`warn`]||0,i=n[e]||0;i>0&&r>=i&&console[e](...t)}async buildAuthorizationUrl(e){await this.storage.hydrate();let t=x(),n=await C(t),r=S(),i=this.config.nonce||S();await this.storage.setItem(u.CODE_VERIFIER,t),await this.storage.setItem(u.STATE,r),await this.storage.setItem(u.NONCE,i);let a=new URLSearchParams({client_id:this.config.clientId,redirect_uri:this.config.redirectUri,response_type:this.config.responseType||`code`,code_challenge_method:this.config.codeChallengeMethod||`S256`,code_challenge:n,state:r,nonce:i});if(this.config.theme){let e=typeof this.config.theme==`function`?this.config.theme():this.config.theme;e&&a.append(`theme`,e)}let o=e?.scope??this.config.scope,s=e?.audience??this.config.audience;return o&&a.append(`scope`,o),s&&a.append(`audience`,s),e?.prompt&&a.append(`prompt`,e.prompt),`${this.config.authorizationEndpoint}?${a.toString()}`}async authorize(e){if(!this.config.openAuthSession)throw Error(`No openAuthSession launcher configured. Pass createExpoWebBrowserLauncher(WebBrowser) or createInAppBrowserLauncher(InAppBrowser) in OAuth2NativeConfig.`);let t=await this.buildAuthorizationUrl(e),n=await this.config.openAuthSession(t,this.config.redirectUri);if(n.type!==`success`||!n.url)throw await this.storage.clearTemporary(),Error(`Authentication ${n.type}`);return this.handleCallbackUrl(n.url)}async handleCallbackUrl(e){let{code:t,state:n,error:r,errorDescription:i}=N(e);if(r)throw await this.storage.clearTemporary(),Error(i?`${r}: ${i}`:r);if(!t||!n)throw await this.storage.clearTemporary(),Error(`Callback URL is missing required code or state parameters.`);return this.exchangeCodeForTokens(t,n)}async exchangeCodeForTokens(e,t){await this.storage.hydrate();let n=await this.storage.getItem(u.STATE),r=await this.storage.getItem(u.CODE_VERIFIER);if(!n||t!==n)throw await this.storage.clearTemporary(),Error(`Invalid state parameter. Possible CSRF attack.`);if(!r)throw await this.storage.clearTemporary(),Error(`Code verifier missing from storage.`);let i=new URLSearchParams({grant_type:`authorization_code`,client_id:this.config.clientId,redirect_uri:this.config.redirectUri,code:e,code_verifier:r}),a=await fetch(this.config.tokenEndpoint,{method:`POST`,headers:{"Content-Type":`application/x-www-form-urlencoded`},body:i.toString()});if(!a.ok)throw Error(`Failed to exchange code for tokens`);let o=await a.json(),s={accessToken:o.access_token,refreshToken:o.refresh_token,tokenType:o.token_type||`Bearer`,expiresAt:Date.now()+o.expires_in*1e3,scope:o.scope,idToken:o.id_token};return await this.saveTokenInfo(s),await this.storage.clearTemporary(),s}async refreshAccessToken(){return this.refreshPromise||=(async()=>{await this.storage.hydrate();let e=await this.storage.getItem(u.REFRESH_TOKEN);if(!e)throw Error(`No refresh token available`);let t=new URLSearchParams({grant_type:`refresh_token`,client_id:this.config.clientId,refresh_token:e}),n;try{n=await fetch(this.config.tokenEndpoint,{method:`POST`,headers:{"Content-Type":`application/x-www-form-urlencoded`},body:t.toString()})}catch(e){throw this.log(`error`,`Token refresh network request failed:`,e),e}if(!n.ok){let e={};try{e=await n.json()}catch{try{e={error:await n.text()}}catch{e={}}}this.log(`error`,`Token refresh failed with status:`,n.status,e),(n.status===400||n.status===401)&&await this.storage.clearTokens();let t=e.error_description||e.error||n.statusText||`Failed to refresh token`;throw Error(`Failed to refresh token (${n.status}): ${t}`)}let r=await n.json(),i={accessToken:r.access_token,refreshToken:r.refresh_token||e,tokenType:r.token_type||`Bearer`,expiresAt:Date.now()+r.expires_in*1e3,scope:r.scope,idToken:r.id_token};return await this.saveTokenInfo(i),i})().finally(()=>{this.refreshPromise=null}),this.refreshPromise}async saveTokenInfo(e){await this.storage.setItem(u.ACCESS_TOKEN,e.accessToken),await this.storage.setItem(u.TOKEN_EXPIRES_AT,e.expiresAt.toString()),await this.storage.setItem(u.TOKEN_TYPE,e.tokenType),e.refreshToken&&await this.storage.setItem(u.REFRESH_TOKEN,e.refreshToken),e.scope&&await this.storage.setItem(u.SCOPE,e.scope),e.idToken&&await this.storage.setItem(u.ID_TOKEN,e.idToken)}getAccessToken(){return this.storage.getItemSync(u.ACCESS_TOKEN)}getIdToken(){return this.storage.getItemSync(u.ID_TOKEN)}getUserProfile(){return y(this.getIdToken()||this.getAccessToken())}getRefreshToken(){return this.storage.getItemSync(u.REFRESH_TOKEN)}getExpiresAt(){let e=this.storage.getItemSync(u.TOKEN_EXPIRES_AT);if(!e)return null;let t=Number(e);return Number.isFinite(t)?t:null}isAuthenticated(){let e=this.getExpiresAt();return e!==null&&Date.now()<e-3e4&&!!this.getAccessToken()}async navigateToAccountManagement(){await this.storage.hydrate();let e=await this.storage.getItem(u.REFRESH_TOKEN);if(!e)throw Error(`No refresh token available to access account management.`);if(!this.config.openAuthSession)throw Error(`No openAuthSession launcher configured. Pass createExpoWebBrowserLauncher(WebBrowser) or createInAppBrowserLauncher(InAppBrowser) in OAuth2NativeConfig.`);let t=this.config.authorizationEndpoint.replace(/\/authorize\/?$/,``),n=await fetch(`${t}/account/ticket`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({refreshToken:e,clientId:this.config.clientId,redirectUri:this.config.redirectUri})});if(!n.ok)throw Error(`Failed to request account management ticket (${n.status})`);let{ticket:r}=await n.json();if(!r)throw Error(`Account management ticket missing from server response.`);let i=`${t}/account?ticket=${encodeURIComponent(r)}&return_to=${encodeURIComponent(this.config.redirectUri)}`;await this.config.openAuthSession(i,this.config.redirectUri)}async logout(e){await this.storage.hydrate();let t=this.getAccessToken(),n=await this.storage.getItem(u.REFRESH_TOKEN);if(await this.storage.clearTokens(),await this.storage.clearTemporary(),this.config.revokeEndpoint){let e=[...n?[{token:n,token_type_hint:`refresh_token`}]:[],...t?[{token:t,token_type_hint:`access_token`}]:[]];for(let t of e)try{await fetch(this.config.revokeEndpoint,{method:`POST`,headers:{"Content-Type":`application/x-www-form-urlencoded`},body:new URLSearchParams({token:t.token,token_type_hint:t.token_type_hint,client_id:this.config.clientId}).toString()})}catch(e){this.log(`error`,`Failed to revoke token during logout`,e)}}if(e?.clearBrowserSession&&this.config.logoutEndpoint&&this.config.openAuthSession){let e=new URLSearchParams({client_id:this.config.clientId,redirect_uri:this.config.redirectUri}),t=this.config.logoutEndpoint.includes(`?`)?`&`:`?`,n=`${this.config.logoutEndpoint}${t}${e.toString()}`;try{await this.config.openAuthSession(n,this.config.redirectUri)}catch(e){this.log(`warn`,`Browser logout session dismissed or failed`,e)}}}},F=(0,t.createContext)(null),I=({config:e,client:r,children:i,onLoginSuccess:a,onLoginError:o,subscribeAppState:s})=>{let[c]=(0,t.useState)(()=>{if(r)return r;if(e)return new P(e);throw Error("AuthProvider requires either a `client` or `config` prop.")}),[l,u]=(0,t.useState)(!1),[d,f]=(0,t.useState)(null),[p,m]=(0,t.useState)(null),[h,g]=(0,t.useState)(null),[_,v]=(0,t.useState)(!0),[y,b]=(0,t.useState)(null),x=(0,t.useCallback)(async()=>{if(await c.initialize(),c.isAuthenticated())u(!0),f(c.getAccessToken()),m(c.getIdToken()),g(c.getUserProfile());else{if(c.getRefreshToken())try{let e=await c.refreshAccessToken();u(!0),f(e.accessToken),m(c.getIdToken()),g(c.getUserProfile());return}catch{u(!1),f(null),m(null),g(null);return}u(!1),f(null),m(null),g(null)}},[c]);(0,t.useEffect)(()=>{let e=!0;return(async()=>{try{await x()}finally{e&&v(!1)}})(),()=>{e=!1}},[x]),(0,t.useEffect)(()=>{if(!l)return;let e,t=()=>{let n=c.getExpiresAt();if(!n)return;let r=n-Date.now()-6e4;e=setTimeout(async()=>{try{let e=await c.refreshAccessToken();f(e.accessToken),m(c.getIdToken()),g(c.getUserProfile()),u(!0),t()}catch(n){c.log(`error`,`Background token refresh failed:`,n),c.getAccessToken()?e=setTimeout(t,3e4):(u(!1),f(null),m(null),g(null))}},Math.max(0,r))};t();let n=s?s(e=>{e===`active`&&x().catch(()=>{})}):void 0;return()=>{e&&clearTimeout(e),n&&n()}},[l,c,s,x]);let S=(0,t.useCallback)(async e=>{v(!0),b(null);try{let t=await c.authorize(e);f(t.accessToken),m(c.getIdToken()),g(c.getUserProfile()),u(!0),a?.()}catch(e){let t=e instanceof Error?e:Error(`Authentication failed`);b(t),o?.(t)}finally{v(!1)}},[c,a,o]),C=(0,t.useCallback)(async e=>{v(!0);try{await c.logout(e),u(!1),f(null),m(null),g(null)}catch(e){b(e instanceof Error?e:Error(`Logout failed`))}finally{v(!1)}},[c]),w=(0,t.useCallback)(async()=>{if(await c.initialize(),c.isAuthenticated())return c.getAccessToken();try{let e=await c.refreshAccessToken();return f(e.accessToken),m(c.getIdToken()),g(c.getUserProfile()),u(!0),e.accessToken}catch{return u(!1),f(null),m(null),g(null),null}},[c]),T=(0,t.useCallback)(async()=>{await c.navigateToAccountManagement(),await x()},[c,x]);return(0,n.jsx)(F.Provider,{value:{isAuthenticated:l,isLoading:_,accessToken:d,idToken:p,user:h,error:y,login:S,logout:C,getToken:w,navigateToAccountManagement:T,authClient:c},children:i})},L=()=>{let e=(0,t.useContext)(F);if(!e)throw Error(`useAuth must be used within an AuthProvider`);return e};function R(e,t,n={}){let r=!1,i=[],a=(e,t=null)=>{i.forEach(n=>{e?n.reject(e):n.resolve(t)}),i=[]},o=e=>!e||!n.excludeUrls?!1:n.excludeUrls.some(t=>typeof t==`string`?e.includes(t):t.test(e)),s=e.interceptors.request.use(async e=>{if(o(e.url))return e;await t.initialize();let n=t.getAccessToken();if(!t.isAuthenticated()&&n)try{n=(await t.refreshAccessToken()).accessToken}catch{n=null}return n&&e.headers.set(`Authorization`,`Bearer ${n}`),e},e=>Promise.reject(e)),c=e.interceptors.response.use(e=>e,async s=>{let c=s.config;if(!c||o(c.url))return Promise.reject(s);if(s.response?.status===401&&!c._retry){if(r)return new Promise((e,t)=>{i.push({resolve:e,reject:t})}).then(t=>(t&&c.headers.set(`Authorization`,`Bearer ${t}`),e(c))).catch(e=>Promise.reject(e));c._retry=!0,r=!0;try{let n=(await t.refreshAccessToken()).accessToken;return a(null,n),c.headers.set(`Authorization`,`Bearer ${n}`),e(c)}catch(e){return a(e,null),await t.logout(),n.onUnauthorized&&n.onUnauthorized(),Promise.reject(e)}finally{r=!1}}return Promise.reject(s)});return()=>{e.interceptors.request.eject(s),e.interceptors.response.eject(c)}}e.AuthClient=P,e.AuthProvider=I,e.NativeTokenStorage=T,e.STORAGE_KEYS=u,e.base64UrlEncode=g,e.createCodeChallenge=C,e.createExpoSecureStoreAdapter=k,e.createExpoWebBrowserLauncher=j,e.createInAppBrowserLauncher=M,e.createKeychainStorageAdapter=A,e.createMemoryStorageAdapter=E,e.decodeJwtPayload=y,e.generateCodeVerifier=x,e.generateRandomString=b,e.generateState=S,e.getRandomBytes=_,e.parseCallbackUrl=N,e.setupAxiosInterceptors=R,e.sha256Bytes=h,e.useAuth=L});
@@ -91,6 +91,33 @@ export interface TokenInfo {
91
91
  scope?: string;
92
92
  idToken?: string;
93
93
  }
94
+ export interface UserProfile {
95
+ sub?: string;
96
+ name?: string;
97
+ given_name?: string;
98
+ family_name?: string;
99
+ email?: string;
100
+ email_verified?: boolean;
101
+ phone_number?: string;
102
+ phone_number_verified?: boolean;
103
+ roles?: string[];
104
+ permissions?: string[];
105
+ amr?: string[];
106
+ act?: {
107
+ sub: string;
108
+ ticket_ref?: string;
109
+ [key: string]: unknown;
110
+ };
111
+ [key: string]: unknown;
112
+ }
113
+ export interface AuthorizeOptions {
114
+ prompt?: 'login' | 'consent' | 'select_account';
115
+ scope?: string;
116
+ audience?: string;
117
+ }
118
+ export interface LogoutOptions {
119
+ clearBrowserSession?: boolean;
120
+ }
94
121
  export declare const STORAGE_KEYS: {
95
122
  readonly ACCESS_TOKEN: 'witsauth_access_token';
96
123
  readonly REFRESH_TOKEN: 'witsauth_refresh_token';
@@ -1,13 +1,15 @@
1
1
  import React from 'react';
2
2
  import { AuthClient } from '../core/AuthClient';
3
- import { OAuth2NativeConfig } from '../models/types';
3
+ import { AuthorizeOptions, LogoutOptions, OAuth2NativeConfig, UserProfile } from '../models/types';
4
4
  export interface AuthContextType {
5
5
  isAuthenticated: boolean;
6
6
  isLoading: boolean;
7
7
  accessToken: string | null;
8
+ idToken: string | null;
9
+ user: UserProfile | null;
8
10
  error: Error | null;
9
- login: () => Promise<void>;
10
- logout: () => Promise<void>;
11
+ login: (options?: AuthorizeOptions) => Promise<void>;
12
+ logout: (options?: LogoutOptions) => Promise<void>;
11
13
  getToken: () => Promise<string | null>;
12
14
  navigateToAccountManagement: () => Promise<void>;
13
15
  authClient: AuthClient;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@witsauth/react-native-client",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Official React Native client library (Expo and Bare React Native CLI) for integrating WitsAuth OAuth 2.0 + PKCE authentication on Android and iOS.",
5
5
  "main": "./dist/index.umd.js",
6
6
  "module": "./dist/index.es.js",
@@ -15,12 +15,6 @@
15
15
  "files": [
16
16
  "dist"
17
17
  ],
18
- "scripts": {
19
- "dev": "vite",
20
- "build": "tsc && vite build && tsc -p tsconfig.build.json",
21
- "test": "vitest run",
22
- "prepublishOnly": "pnpm test && pnpm build"
23
- },
24
18
  "publishConfig": {
25
19
  "access": "public"
26
20
  },
@@ -61,5 +55,10 @@
61
55
  "typescript": "^7.0.2",
62
56
  "vite": "^8.1.5",
63
57
  "vitest": "^4.1.10"
58
+ },
59
+ "scripts": {
60
+ "dev": "vite",
61
+ "build": "tsc && vite build && tsc -p tsconfig.build.json",
62
+ "test": "vitest run"
64
63
  }
65
- }
64
+ }