@authu/react 1.0.68 → 1.0.69

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 +1 @@
1
- {"version":3,"file":"AuthUProvider.d.ts","sourceRoot":"","sources":["../src/AuthUProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,SAAS,EAKf,MAAM,OAAO,CAAC;AAef,OAAO,KAAK,EAEV,WAAW,EACX,iBAAiB,EAKlB,MAAM,YAAY,CAAC;AAEpB,eAAO,MAAM,YAAY,mDAAgD,CAAC;AAW1E,UAAU,kBAAkB;IAC1B,MAAM,EAAE,WAAW,CAAC;IACpB,QAAQ,EAAE,SAAS,CAAC;CACrB;AAuDD,wBAAgB,aAAa,CAAC,EAAC,MAAM,EAAE,QAAQ,EAAC,EAAE,kBAAkB,2CA6ZnE"}
1
+ {"version":3,"file":"AuthUProvider.d.ts","sourceRoot":"","sources":["../src/AuthUProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,SAAS,EAKf,MAAM,OAAO,CAAC;AAef,OAAO,KAAK,EAEV,WAAW,EACX,iBAAiB,EAKlB,MAAM,YAAY,CAAC;AAEpB,eAAO,MAAM,YAAY,mDAAgD,CAAC;AAW1E,UAAU,kBAAkB;IAC1B,MAAM,EAAE,WAAW,CAAC;IACpB,QAAQ,EAAE,SAAS,CAAC;CACrB;AA2DD,wBAAgB,aAAa,CAAC,EAAC,MAAM,EAAE,QAAQ,EAAC,EAAE,kBAAkB,2CAobnE"}
@@ -38,6 +38,9 @@ const EMPTY_STATE = {
38
38
  function currentLocation() {
39
39
  return `${window.location.pathname}${window.location.search}${window.location.hash}`;
40
40
  }
41
+ function toError(err, fallback) {
42
+ return err instanceof Error ? err : new Error(fallback);
43
+ }
41
44
  /**
42
45
  * Only a same-origin path is ever restored: `//evil.example` is a valid
43
46
  * relative URL for the browser but a different origin, so a poisoned entry
@@ -143,7 +146,17 @@ export function AuthUProvider({ config, children }) {
143
146
  if (options?.returnTo) {
144
147
  sessionStorage.setItem(RETURN_TO_KEY, options.returnTo);
145
148
  }
146
- window.location.href = await buildAuthorizationUrl(options);
149
+ try {
150
+ window.location.href = await buildAuthorizationUrl(options);
151
+ }
152
+ catch (err) {
153
+ setState(prev => ({
154
+ ...prev,
155
+ isLoading: false,
156
+ error: toError(err, 'Login failed')
157
+ }));
158
+ throw err;
159
+ }
147
160
  }, [buildAuthorizationUrl]);
148
161
  /**
149
162
  * A local logout is no longer enough: the session now lives in AuthU's own
@@ -289,8 +302,14 @@ export function AuthUProvider({ config, children }) {
289
302
  // Read and clear the verifier in one go: React StrictMode mounts this
290
303
  // effect twice, and the second pass must not replay the same code.
291
304
  const codeVerifier = getCodeVerifier();
292
- if (!codeVerifier)
305
+ if (!codeVerifier) {
306
+ restoreUrl();
307
+ setState({
308
+ ...EMPTY_STATE,
309
+ error: new Error('Missing PKCE code verifier')
310
+ });
293
311
  return;
312
+ }
294
313
  clearCodeVerifier();
295
314
  clearState();
296
315
  clearNonce();
@@ -309,7 +328,7 @@ export function AuthUProvider({ config, children }) {
309
328
  catch (err) {
310
329
  setState({
311
330
  ...EMPTY_STATE,
312
- error: err instanceof Error ? err : new Error('Authentication failed')
331
+ error: toError(err, 'Authentication failed')
313
332
  });
314
333
  }
315
334
  return;
@@ -323,7 +342,15 @@ export function AuthUProvider({ config, children }) {
323
342
  sessionStorage.setItem(RETURN_TO_KEY, currentLocation());
324
343
  window.location.replace(await buildAuthorizationUrl({ prompt: 'none' }));
325
344
  };
326
- bootstrap();
345
+ // Anything thrown while starting up (storage access, the PKCE challenge,
346
+ // URL rewriting) must still end the loading state, or the host app spins
347
+ // forever without a single request leaving the page.
348
+ bootstrap().catch(err => {
349
+ setState({
350
+ ...EMPTY_STATE,
351
+ error: toError(err, 'Authentication failed')
352
+ });
353
+ });
327
354
  }, [
328
355
  buildAuthorizationUrl,
329
356
  exchangeCodeForTokensWithVerifier,
package/dist/pkce.d.ts CHANGED
@@ -1,3 +1,12 @@
1
+ /**
2
+ * Plain SHA-256 (FIPS 180-4), only used where crypto.subtle is missing.
3
+ * Browsers expose crypto.subtle in secure contexts only, so a dev server
4
+ * reached over the LAN (a phone opening http://192.168.x.x) has none, while
5
+ * crypto.getRandomValues is still there: without this fallback the challenge
6
+ * throws and sign-in never starts.
7
+ */
8
+ export declare function sha256Fallback(data: Uint8Array): ArrayBuffer;
9
+ export declare function base64UrlEncode(buffer: ArrayBuffer): string;
1
10
  export declare function generateCodeVerifier(): string;
2
11
  export declare function generateCodeChallenge(verifier: string): Promise<string>;
3
12
  export declare function generateState(): string;
@@ -1 +1 @@
1
- {"version":3,"file":"pkce.d.ts","sourceRoot":"","sources":["../src/pkce.ts"],"names":[],"mappings":"AA2BA,wBAAgB,oBAAoB,IAAI,MAAM,CAE7C;AAED,wBAAsB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAG7E;AAED,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAcD,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAExD;AAED,wBAAgB,eAAe,IAAI,MAAM,GAAG,IAAI,CAE/C;AAED,wBAAgB,iBAAiB,IAAI,IAAI,CAExC;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAE9C;AAED,wBAAgB,cAAc,IAAI,MAAM,GAAG,IAAI,CAE9C;AAED,wBAAgB,UAAU,IAAI,IAAI,CAEjC;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAE9C;AAED,wBAAgB,cAAc,IAAI,MAAM,GAAG,IAAI,CAE9C;AAED,wBAAgB,UAAU,IAAI,IAAI,CAEjC"}
1
+ {"version":3,"file":"pkce.d.ts","sourceRoot":"","sources":["../src/pkce.ts"],"names":[],"mappings":"AAyBA;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,UAAU,GAAG,WAAW,CA0D5D;AAWD,wBAAgB,eAAe,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAU3D;AAED,wBAAgB,oBAAoB,IAAI,MAAM,CAE7C;AAED,wBAAsB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAG7E;AAED,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAcD,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAExD;AAED,wBAAgB,eAAe,IAAI,MAAM,GAAG,IAAI,CAE/C;AAED,wBAAgB,iBAAiB,IAAI,IAAI,CAExC;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAE9C;AAED,wBAAgB,cAAc,IAAI,MAAM,GAAG,IAAI,CAE9C;AAED,wBAAgB,UAAU,IAAI,IAAI,CAEjC;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAE9C;AAED,wBAAgB,cAAc,IAAI,MAAM,GAAG,IAAI,CAE9C;AAED,wBAAgB,UAAU,IAAI,IAAI,CAEjC"}
package/dist/pkce.js CHANGED
@@ -5,12 +5,90 @@ function generateRandomString(length) {
5
5
  .map(v => charset[v % charset.length])
6
6
  .join('');
7
7
  }
8
+ const SHA256_K = new Uint32Array([
9
+ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1,
10
+ 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
11
+ 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
12
+ 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
13
+ 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,
14
+ 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
15
+ 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
16
+ 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
17
+ 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,
18
+ 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
19
+ 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
20
+ ]);
21
+ const rotr = (x, n) => (x >>> n) | (x << (32 - n));
22
+ /**
23
+ * Plain SHA-256 (FIPS 180-4), only used where crypto.subtle is missing.
24
+ * Browsers expose crypto.subtle in secure contexts only, so a dev server
25
+ * reached over the LAN (a phone opening http://192.168.x.x) has none, while
26
+ * crypto.getRandomValues is still there: without this fallback the challenge
27
+ * throws and sign-in never starts.
28
+ */
29
+ export function sha256Fallback(data) {
30
+ const bitLength = data.length * 8;
31
+ const padded = new Uint8Array(Math.ceil((data.length + 9) / 64) * 64);
32
+ padded.set(data);
33
+ padded[data.length] = 0x80;
34
+ const view = new DataView(padded.buffer);
35
+ view.setUint32(padded.length - 8, Math.floor(bitLength / 0x100000000));
36
+ view.setUint32(padded.length - 4, bitLength >>> 0);
37
+ const h = new Uint32Array([
38
+ 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c,
39
+ 0x1f83d9ab, 0x5be0cd19
40
+ ]);
41
+ const w = new Uint32Array(64);
42
+ for (let offset = 0; offset < padded.length; offset += 64) {
43
+ for (let t = 0; t < 16; t++) {
44
+ w[t] = view.getUint32(offset + t * 4);
45
+ }
46
+ for (let t = 16; t < 64; t++) {
47
+ const s0 = rotr(w[t - 15], 7) ^ rotr(w[t - 15], 18) ^ (w[t - 15] >>> 3);
48
+ const s1 = rotr(w[t - 2], 17) ^ rotr(w[t - 2], 19) ^ (w[t - 2] >>> 10);
49
+ w[t] = w[t - 16] + s0 + w[t - 7] + s1;
50
+ }
51
+ let [a, b, c, d, e, f, g, hh] = h;
52
+ for (let t = 0; t < 64; t++) {
53
+ const S1 = rotr(e, 6) ^ rotr(e, 11) ^ rotr(e, 25);
54
+ const ch = (e & f) ^ (~e & g);
55
+ const temp1 = (hh + S1 + ch + SHA256_K[t] + w[t]) >>> 0;
56
+ const S0 = rotr(a, 2) ^ rotr(a, 13) ^ rotr(a, 22);
57
+ const maj = (a & b) ^ (a & c) ^ (b & c);
58
+ const temp2 = (S0 + maj) >>> 0;
59
+ hh = g;
60
+ g = f;
61
+ f = e;
62
+ e = (d + temp1) >>> 0;
63
+ d = c;
64
+ c = b;
65
+ b = a;
66
+ a = (temp1 + temp2) >>> 0;
67
+ }
68
+ h[0] += a;
69
+ h[1] += b;
70
+ h[2] += c;
71
+ h[3] += d;
72
+ h[4] += e;
73
+ h[5] += f;
74
+ h[6] += g;
75
+ h[7] += hh;
76
+ }
77
+ const digest = new DataView(new ArrayBuffer(32));
78
+ for (let i = 0; i < 8; i++) {
79
+ digest.setUint32(i * 4, h[i]);
80
+ }
81
+ return digest.buffer;
82
+ }
8
83
  async function sha256(plain) {
9
84
  const encoder = new TextEncoder();
10
85
  const data = encoder.encode(plain);
86
+ if (!globalThis.crypto?.subtle) {
87
+ return sha256Fallback(data);
88
+ }
11
89
  return crypto.subtle.digest('SHA-256', data);
12
90
  }
13
- function base64UrlEncode(buffer) {
91
+ export function base64UrlEncode(buffer) {
14
92
  const bytes = new Uint8Array(buffer);
15
93
  let binary = '';
16
94
  for (let i = 0; i < bytes.byteLength; i++) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@authu/react",
3
- "version": "1.0.68",
3
+ "version": "1.0.69",
4
4
  "description": "React SDK for AuthU - Centralized Multi-Tenant Authentication Service",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -18,8 +18,9 @@
18
18
  "scripts": {
19
19
  "build": "tsc",
20
20
  "dev": "tsc --watch",
21
- "lint": "biome check src && tsc --noEmit",
22
- "lint:fix": "biome check --write src",
21
+ "lint": "biome check src test && tsc --noEmit",
22
+ "lint:fix": "biome check --write src test",
23
+ "test": "node --test 'test/**/*.test.ts'",
23
24
  "format": "biome format --write src",
24
25
  "format:check": "biome format --check src",
25
26
  "typecheck": "tsc --noEmit",