@authu/react 1.0.67 → 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.
- package/dist/AuthUProvider.d.ts.map +1 -1
- package/dist/AuthUProvider.js +35 -5
- package/dist/pkce.d.ts +9 -0
- package/dist/pkce.d.ts.map +1 -1
- package/dist/pkce.js +79 -1
- package/package.json +4 -3
|
@@ -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;
|
|
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"}
|
package/dist/AuthUProvider.js
CHANGED
|
@@ -2,8 +2,11 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import { createContext, useCallback, useEffect, useRef, useState } from 'react';
|
|
3
3
|
import { clearCodeVerifier, clearNonce, clearState, generateCodeChallenge, generateCodeVerifier, generateNonce, generateState, getCodeVerifier, getStoredState, storeCodeVerifier, storeNonce, storeState } from './pkce.js';
|
|
4
4
|
export const AuthUContext = createContext(null);
|
|
5
|
+
// A bare IP address is a local dev server reached over the LAN (a phone
|
|
6
|
+
// testing against a laptop): like localhost, it has no certificate.
|
|
7
|
+
const LOCAL_DOMAIN = /^(localhost|\d{1,3}(\.\d{1,3}){3})(:\d+)?$/;
|
|
5
8
|
function buildBaseUrl(domain) {
|
|
6
|
-
const protocol =
|
|
9
|
+
const protocol = LOCAL_DOMAIN.test(domain) ? 'http' : 'https';
|
|
7
10
|
return `${protocol}://${domain}`;
|
|
8
11
|
}
|
|
9
12
|
/**
|
|
@@ -35,6 +38,9 @@ const EMPTY_STATE = {
|
|
|
35
38
|
function currentLocation() {
|
|
36
39
|
return `${window.location.pathname}${window.location.search}${window.location.hash}`;
|
|
37
40
|
}
|
|
41
|
+
function toError(err, fallback) {
|
|
42
|
+
return err instanceof Error ? err : new Error(fallback);
|
|
43
|
+
}
|
|
38
44
|
/**
|
|
39
45
|
* Only a same-origin path is ever restored: `//evil.example` is a valid
|
|
40
46
|
* relative URL for the browser but a different origin, so a poisoned entry
|
|
@@ -140,7 +146,17 @@ export function AuthUProvider({ config, children }) {
|
|
|
140
146
|
if (options?.returnTo) {
|
|
141
147
|
sessionStorage.setItem(RETURN_TO_KEY, options.returnTo);
|
|
142
148
|
}
|
|
143
|
-
|
|
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
|
+
}
|
|
144
160
|
}, [buildAuthorizationUrl]);
|
|
145
161
|
/**
|
|
146
162
|
* A local logout is no longer enough: the session now lives in AuthU's own
|
|
@@ -286,8 +302,14 @@ export function AuthUProvider({ config, children }) {
|
|
|
286
302
|
// Read and clear the verifier in one go: React StrictMode mounts this
|
|
287
303
|
// effect twice, and the second pass must not replay the same code.
|
|
288
304
|
const codeVerifier = getCodeVerifier();
|
|
289
|
-
if (!codeVerifier)
|
|
305
|
+
if (!codeVerifier) {
|
|
306
|
+
restoreUrl();
|
|
307
|
+
setState({
|
|
308
|
+
...EMPTY_STATE,
|
|
309
|
+
error: new Error('Missing PKCE code verifier')
|
|
310
|
+
});
|
|
290
311
|
return;
|
|
312
|
+
}
|
|
291
313
|
clearCodeVerifier();
|
|
292
314
|
clearState();
|
|
293
315
|
clearNonce();
|
|
@@ -306,7 +328,7 @@ export function AuthUProvider({ config, children }) {
|
|
|
306
328
|
catch (err) {
|
|
307
329
|
setState({
|
|
308
330
|
...EMPTY_STATE,
|
|
309
|
-
error: err
|
|
331
|
+
error: toError(err, 'Authentication failed')
|
|
310
332
|
});
|
|
311
333
|
}
|
|
312
334
|
return;
|
|
@@ -320,7 +342,15 @@ export function AuthUProvider({ config, children }) {
|
|
|
320
342
|
sessionStorage.setItem(RETURN_TO_KEY, currentLocation());
|
|
321
343
|
window.location.replace(await buildAuthorizationUrl({ prompt: 'none' }));
|
|
322
344
|
};
|
|
323
|
-
|
|
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
|
+
});
|
|
324
354
|
}, [
|
|
325
355
|
buildAuthorizationUrl,
|
|
326
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;
|
package/dist/pkce.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pkce.d.ts","sourceRoot":"","sources":["../src/pkce.ts"],"names":[],"mappings":"
|
|
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.
|
|
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",
|