@tidecloak/js 0.14.41 → 0.14.42-staging
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/README.md +32 -47
- package/dist/cjs/lib/tidecloak-dpop.js +151 -42
- package/dist/cjs/lib/tidecloak-dpop.js.map +1 -1
- package/dist/cjs/lib/tidecloak.js +300 -378
- package/dist/cjs/lib/tidecloak.js.map +1 -1
- package/dist/cjs/src/AdminAPI.js +12 -19
- package/dist/cjs/src/AdminAPI.js.map +1 -1
- package/dist/cjs/src/IAMService.js +155 -2098
- package/dist/cjs/src/IAMService.js.map +1 -1
- package/dist/cjs/src/index.js +1 -7
- package/dist/cjs/src/index.js.map +1 -1
- package/dist/esm/lib/tidecloak-dpop.js +151 -42
- package/dist/esm/lib/tidecloak-dpop.js.map +1 -1
- package/dist/esm/lib/tidecloak.js +300 -377
- package/dist/esm/lib/tidecloak.js.map +1 -1
- package/dist/esm/src/AdminAPI.js +3 -7
- package/dist/esm/src/AdminAPI.js.map +1 -1
- package/dist/esm/src/IAMService.js +152 -2065
- package/dist/esm/src/IAMService.js.map +1 -1
- package/dist/esm/src/index.js +1 -7
- package/dist/esm/src/index.js.map +1 -1
- package/dist/types/AdminAPI.d.ts +1 -1
- package/dist/types/IAMService.d.ts +52 -603
- package/dist/types/index.d.ts +1 -11
- package/dist/types/lib/tidecloak-dpop.d.ts +19 -3
- package/dist/types/lib/tidecloak.d.ts +46 -38
- package/dist/types/src/AdminAPI.d.ts +1 -1
- package/dist/types/src/IAMService.d.ts +52 -603
- package/dist/types/src/index.d.ts +1 -11
- package/docs/FRONT_CHANNEL.md +55 -55
- package/lib/README.md +10 -14
- package/package.json +4 -25
- package/dist/cjs/lib/secureFetchPolicy.js +0 -45
- package/dist/cjs/lib/secureFetchPolicy.js.map +0 -1
- package/dist/cjs/src/dpopRoute.js +0 -30
- package/dist/cjs/src/dpopRoute.js.map +0 -1
- package/dist/cjs/src/dpopServer.js +0 -77
- package/dist/cjs/src/dpopServer.js.map +0 -1
- package/dist/cjs/src/generated/dpopAuthAsset.js +0 -7
- package/dist/cjs/src/generated/dpopAuthAsset.js.map +0 -1
- package/dist/cjs/src/policy-react.js +0 -51
- package/dist/cjs/src/policy-react.js.map +0 -1
- package/dist/cjs/src/types.js +0 -6
- package/dist/cjs/src/types.js.map +0 -1
- package/dist/cjs/src/utils/dpopAuthPage.js +0 -69
- package/dist/cjs/src/utils/dpopAuthPage.js.map +0 -1
- package/dist/cjs/src/utils/fetch.js +0 -39
- package/dist/cjs/src/utils/fetch.js.map +0 -1
- package/dist/cjs/src/utils/index.js +0 -17
- package/dist/cjs/src/utils/index.js.map +0 -1
- package/dist/cjs/src/utils/initOptions.js +0 -78
- package/dist/cjs/src/utils/initOptions.js.map +0 -1
- package/dist/cjs/src/utils/pkce.js +0 -48
- package/dist/cjs/src/utils/pkce.js.map +0 -1
- package/dist/cjs/src/utils/silentCheckSso.js +0 -138
- package/dist/cjs/src/utils/silentCheckSso.js.map +0 -1
- package/dist/cjs/src/vite.js +0 -43
- package/dist/cjs/src/vite.js.map +0 -1
- package/dist/esm/lib/secureFetchPolicy.js +0 -42
- package/dist/esm/lib/secureFetchPolicy.js.map +0 -1
- package/dist/esm/src/dpopRoute.js +0 -27
- package/dist/esm/src/dpopRoute.js.map +0 -1
- package/dist/esm/src/dpopServer.js +0 -68
- package/dist/esm/src/dpopServer.js.map +0 -1
- package/dist/esm/src/generated/dpopAuthAsset.js +0 -4
- package/dist/esm/src/generated/dpopAuthAsset.js.map +0 -1
- package/dist/esm/src/policy-react.js +0 -45
- package/dist/esm/src/policy-react.js.map +0 -1
- package/dist/esm/src/types.js +0 -5
- package/dist/esm/src/types.js.map +0 -1
- package/dist/esm/src/utils/dpopAuthPage.js +0 -63
- package/dist/esm/src/utils/dpopAuthPage.js.map +0 -1
- package/dist/esm/src/utils/fetch.js +0 -36
- package/dist/esm/src/utils/fetch.js.map +0 -1
- package/dist/esm/src/utils/index.js +0 -6
- package/dist/esm/src/utils/index.js.map +0 -1
- package/dist/esm/src/utils/initOptions.js +0 -75
- package/dist/esm/src/utils/initOptions.js.map +0 -1
- package/dist/esm/src/utils/pkce.js +0 -43
- package/dist/esm/src/utils/pkce.js.map +0 -1
- package/dist/esm/src/utils/silentCheckSso.js +0 -134
- package/dist/esm/src/utils/silentCheckSso.js.map +0 -1
- package/dist/esm/src/vite.js +0 -40
- package/dist/esm/src/vite.js.map +0 -1
- package/dist/types/dpopRoute.d.ts +0 -11
- package/dist/types/dpopServer.d.ts +0 -35
- package/dist/types/generated/dpopAuthAsset.d.ts +0 -2
- package/dist/types/lib/secureFetchPolicy.d.ts +0 -37
- package/dist/types/policy-react.d.ts +0 -40
- package/dist/types/src/dpopRoute.d.ts +0 -11
- package/dist/types/src/dpopServer.d.ts +0 -35
- package/dist/types/src/generated/dpopAuthAsset.d.ts +0 -2
- package/dist/types/src/policy-react.d.ts +0 -40
- package/dist/types/src/types.d.ts +0 -114
- package/dist/types/src/utils/dpopAuthPage.d.ts +0 -22
- package/dist/types/src/utils/fetch.d.ts +0 -11
- package/dist/types/src/utils/index.d.ts +0 -5
- package/dist/types/src/utils/initOptions.d.ts +0 -69
- package/dist/types/src/utils/pkce.d.ts +0 -24
- package/dist/types/src/utils/silentCheckSso.d.ts +0 -82
- package/dist/types/src/vite.d.ts +0 -13
- package/dist/types/types.d.ts +0 -114
- package/dist/types/utils/dpopAuthPage.d.ts +0 -22
- package/dist/types/utils/fetch.d.ts +0 -11
- package/dist/types/utils/index.d.ts +0 -5
- package/dist/types/utils/initOptions.d.ts +0 -69
- package/dist/types/utils/pkce.d.ts +0 -24
- package/dist/types/utils/silentCheckSso.d.ts +0 -82
- package/dist/types/vite.d.ts +0 -13
- package/docs/HYBRID_MODE.md +0 -185
- package/docs/NATIVE_MODE.md +0 -284
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The decision seam of `TideCloak.secureFetch`: given the caller's `Authorization`
|
|
3
|
-
* header (if any) and the access token this client currently holds, should we sign
|
|
4
|
-
* the request as our own - `Authorization: DPoP <token>` plus a `DPoP:` proof?
|
|
5
|
-
*
|
|
6
|
-
* Kept in its own dependency-free module so it can be unit-tested directly.
|
|
7
|
-
* `lib/tidecloak.js` pulls in `heimdall-tide`, which cannot be loaded under plain
|
|
8
|
-
* node ESM, so the predicate is unreachable from a test if it lives there - and
|
|
9
|
-
* this is precisely the seam where a mistake becomes an unexplainable `401`.
|
|
10
|
-
*/
|
|
11
|
-
/**
|
|
12
|
-
* @param {string|null|undefined} existingAuth - the caller's `Authorization` header.
|
|
13
|
-
* @param {string} ourToken - the access token this client currently holds.
|
|
14
|
-
* @returns {boolean} true -> attach `Authorization: DPoP <ourToken>` + a DPoP proof.
|
|
15
|
-
*
|
|
16
|
-
* Three cases:
|
|
17
|
-
*
|
|
18
|
-
* - NO `Authorization` header: YES, attach. "I set no Authorization, use your
|
|
19
|
-
* token" is the entire point of calling `secureFetch` rather than `fetch`, and
|
|
20
|
-
* it is exactly what `secureFetch`'s own stale-token warning tells callers to do
|
|
21
|
-
* ("omit the Authorization header entirely and let secureFetch attach it").
|
|
22
|
-
*
|
|
23
|
-
* This case used to be false, which sent the request as a plain, UNAUTHENTICATED
|
|
24
|
-
* fetch: no token, no proof, no credentials of any kind. A consumer that reads
|
|
25
|
-
* its token from an async state container and calls before that state has
|
|
26
|
-
* settled (React state that has not yet committed, say) would silently ship a
|
|
27
|
-
* credential-less admin request and get back a bare `401` naming none of this.
|
|
28
|
-
* That is the admin-API 401 this closes.
|
|
29
|
-
*
|
|
30
|
-
* - OUR bearer token: YES, attach - upgrade `Bearer` to `DPoP` + proof. Unchanged.
|
|
31
|
-
*
|
|
32
|
-
* - SOMEONE ELSE'S bearer token: NO. A third-party API call is a legitimate
|
|
33
|
-
* pass-through: it goes out verbatim and must never be handed one of our proofs.
|
|
34
|
-
* Unchanged. (A stale copy of one of ours lands here too, and is warned about
|
|
35
|
-
* once by the caller.)
|
|
36
|
-
*/
|
|
37
|
-
export declare function shouldAttachDpopProof(existingAuth: string | null | undefined, ourToken: string): boolean;
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @deprecated The policy editor is no longer part of @tidecloak/js. This entry
|
|
3
|
-
* point is kept so existing imports still resolve; every component throws when
|
|
4
|
-
* rendered. The @tidecloak/policy package it used to re-export was never
|
|
5
|
-
* published to npm.
|
|
6
|
-
*/
|
|
7
|
-
export type Policy = any;
|
|
8
|
-
export type PolicyBlock = any;
|
|
9
|
-
export type Model = any;
|
|
10
|
-
export type ModelField = any;
|
|
11
|
-
export type Claim = any;
|
|
12
|
-
/** @typedef {any} Policy */
|
|
13
|
-
/** @typedef {any} PolicyBlock */
|
|
14
|
-
/** @typedef {any} Model */
|
|
15
|
-
/** @typedef {any} ModelField */
|
|
16
|
-
/** @typedef {any} Claim */
|
|
17
|
-
/**
|
|
18
|
-
* @deprecated The policy editor has moved out of @tidecloak/js.
|
|
19
|
-
* @param {any} _props
|
|
20
|
-
* @returns {never}
|
|
21
|
-
*/
|
|
22
|
-
export declare function PolicyBuilder(_props: any): never;
|
|
23
|
-
/**
|
|
24
|
-
* @deprecated The policy editor has moved out of @tidecloak/js.
|
|
25
|
-
* @param {any} _props
|
|
26
|
-
* @returns {never}
|
|
27
|
-
*/
|
|
28
|
-
export declare function PolicyCanvas(_props: any): never;
|
|
29
|
-
/**
|
|
30
|
-
* @deprecated The policy editor has moved out of @tidecloak/js.
|
|
31
|
-
* @param {any} _props
|
|
32
|
-
* @returns {never}
|
|
33
|
-
*/
|
|
34
|
-
export declare function PropertiesPanel(_props: any): never;
|
|
35
|
-
/**
|
|
36
|
-
* @deprecated The policy editor has moved out of @tidecloak/js.
|
|
37
|
-
* @param {any} _props
|
|
38
|
-
* @returns {never}
|
|
39
|
-
*/
|
|
40
|
-
export declare function BlockPalette(_props: any): never;
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @param {Object} [options]
|
|
3
|
-
* @param {Object} [options.config] TideCloak adapter config (tidecloak.json). Used to
|
|
4
|
-
* reject requests for another realm or client. Omitted or empty, it serves any.
|
|
5
|
-
*/
|
|
6
|
-
export declare function createDpopRoute({ config }?: {
|
|
7
|
-
config?: Object;
|
|
8
|
-
}): {
|
|
9
|
-
GET: (request: any) => Response;
|
|
10
|
-
HEAD: (request: any) => Response;
|
|
11
|
-
};
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { DPOP_AUTH_HTML, DPOP_AUTH_CSP } from './generated/dpopAuthAsset.js';
|
|
2
|
-
export { DPOP_AUTH_HTML, DPOP_AUTH_CSP };
|
|
3
|
-
export declare function dpopAuthHeaders(): {
|
|
4
|
-
'Content-Type': string;
|
|
5
|
-
'Content-Security-Policy': string;
|
|
6
|
-
'Allow-CSP-From': string;
|
|
7
|
-
'Cache-Control': string;
|
|
8
|
-
};
|
|
9
|
-
export declare function hexToUtf8(hex: any): string | null;
|
|
10
|
-
export declare function dpopAuthPathFor(issuer: any, clientId: any): string;
|
|
11
|
-
/**
|
|
12
|
-
* Issuer and client id to accept, from a TideCloak adapter config.
|
|
13
|
-
* Either is undefined when the config does not carry it (e.g. the `{}` placeholder).
|
|
14
|
-
*/
|
|
15
|
-
export declare function expectationsFromConfig(config?: {}): {
|
|
16
|
-
issuer: string | undefined;
|
|
17
|
-
client: any;
|
|
18
|
-
};
|
|
19
|
-
/**
|
|
20
|
-
* The response for a request path, as `{ status, headers, body }`, or null when
|
|
21
|
-
* the path is not the DPoP page. Omitted expectations are not checked.
|
|
22
|
-
*/
|
|
23
|
-
export declare function resolveDpopAuthRequest({ pathname, expectedIssuer, expectedClient, method }: {
|
|
24
|
-
expectedClient: any;
|
|
25
|
-
expectedIssuer: any;
|
|
26
|
-
method?: string | undefined;
|
|
27
|
-
pathname: any;
|
|
28
|
-
}): {
|
|
29
|
-
status: any;
|
|
30
|
-
headers: {
|
|
31
|
-
'Content-Type': string;
|
|
32
|
-
'Cache-Control': string;
|
|
33
|
-
};
|
|
34
|
-
body: any;
|
|
35
|
-
} | null;
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
export declare const DPOP_AUTH_HTML = "<html>\n\n<head>\n <style>\n body {\n margin: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100vh;\n background: #f6f6f7;\n font-family: -apple-system, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif;\n }\n\n .status {\n text-align: center;\n opacity: 0;\n }\n\n .status.visible {\n opacity: 1;\n }\n\n .checkmark-circle {\n width: 72px;\n height: 72px;\n margin: 0 auto 16px;\n }\n\n .checkmark-circle circle {\n fill: none;\n stroke: #039855;\n stroke-width: 3;\n stroke-dasharray: 201;\n stroke-dashoffset: 201;\n }\n\n .checkmark-circle path {\n fill: none;\n stroke: #039855;\n stroke-width: 3;\n stroke-linecap: round;\n stroke-linejoin: round;\n stroke-dasharray: 50;\n stroke-dashoffset: 50;\n }\n\n .status.visible .checkmark-circle circle {\n animation: circle-draw 0.5s ease forwards;\n }\n\n .status.visible .checkmark-circle path {\n animation: check-draw 0.3s 0.4s ease forwards;\n }\n\n .status.visible .status-text {\n animation: fade-in 0.3s 0.6s ease forwards;\n }\n\n .status-text {\n font-size: 15px;\n color: #464647;\n margin: 0;\n opacity: 0;\n }\n\n @keyframes circle-draw {\n to {\n stroke-dashoffset: 0;\n }\n }\n\n @keyframes check-draw {\n to {\n stroke-dashoffset: 0;\n }\n }\n\n @keyframes fade-in {\n to {\n opacity: 1;\n }\n }\n </style>\n</head>\n\n<body>\n <div class=\"status\" id=\"status\">\n <svg class=\"checkmark-circle\" viewBox=\"0 0 72 72\">\n <circle cx=\"36\" cy=\"36\" r=\"32\" />\n <path d=\"M22 36 l10 10 l18 -20\" />\n </svg>\n <p class=\"status-text\">Session verified</p>\n </div>\n <script>\n const thisVersion = 1;\n\n const hexToStr = (hex) => {\n if (!hex || hex.length % 2 !== 0 || !/^[0-9a-fA-F]+$/.test(hex)) throw Error(\"Invalid hex string\");\n const bytes = new Uint8Array(hex.length / 2);\n for (let i = 0; i < bytes.length; i++) bytes[i] = parseInt(hex.substr(i * 2, 2), 16);\n return new TextDecoder().decode(bytes);\n };\n\n const createDbName = async (issuer, clientId) => {\n const encoder = new TextEncoder();\n const issuerHash = Array.from(new Uint8Array(await crypto.subtle.digest('SHA-256', encoder.encode(issuer))).slice(0, 8))\n .map(b => b.toString(16).padStart(2, '0')).join('');\n const clientHash = Array.from(new Uint8Array(await crypto.subtle.digest('SHA-256', encoder.encode(clientId))).slice(0, 8))\n .map(b => b.toString(16).padStart(2, '0')).join('');\n return `dpop:${issuerHash}:${clientHash}`;\n };\n\n // Determine target window: popup has window.opener, iframe has window.parent\n const isPopup = !!window.opener;\n const targetWindow = window.opener || window.parent;\n\n if (!targetWindow || targetWindow === window) {\n document.body.textContent = \"Error: No parent or opener window found.\";\n throw Error(\"No target window available for postMessage\");\n }\n\n const urlParams = new URL(window.location.href).searchParams;\n const enclaveVersion = urlParams.get(\"version\");\n if (!enclaveVersion) throw Error(\"No enclave version provided in url\");\n let openerOrigin = urlParams.get(\"openerOrigin\");\n if (!openerOrigin) throw Error(\"No opener origin provided in url\");\n openerOrigin = new URL(decodeURIComponent(openerOrigin)).origin;\n\n const showSuccess = () => {\n document.getElementById('status').classList.add('visible');\n };\n\n const version1Flow = async () => {\n const paths = new URL(window.location.href).pathname.split(\"/\");\n const iss = hexToStr(paths[paths.indexOf(\"iss\") + 1]);\n const aud = hexToStr(paths[paths.indexOf(\"aud\") + 1]);\n const dbname = await createDbName(iss, aud);\n let dpopKey;\n try {\n // Chrome 125+: requestStorageAccess({ indexedDB: true }) returns a handle\n // whose .indexedDB factory points directly at the unpartitioned bucket.\n // If permission was already granted (within 30 days) this resolves\n // automatically with no prompt.\n //\n // In popup mode we have first-party context so we can access IndexedDB directly.\n let idbFactory;\n if (isPopup) {\n idbFactory = window.indexedDB;\n } else {\n const handle = await document.requestStorageAccess({ indexedDB: true });\n idbFactory = handle.indexedDB;\n }\n\n const db = await new Promise((resolve, reject) => {\n const req = idbFactory.open(dbname);\n req.onsuccess = () => resolve(req.result);\n req.onerror = () => reject(req.error);\n });\n dpopKey = await new Promise((resolve, reject) => {\n const tx = db.transaction(\"main\", \"readonly\");\n const store = tx.objectStore(\"main\");\n const req = store.get(\"dpopState\");\n req.onsuccess = () => resolve(req.result);\n req.onerror = () => reject(req.error);\n });\n db.close();\n if (!dpopKey || !dpopKey.keys) throw Error(\"No DPoP key found in IndexedDB\");\n } catch (ex) {\n const isStorageBlocked =\n ex?.name === \"NotAllowedError\" ||\n (ex instanceof DOMException && (\n ex.name === \"SecurityError\" ||\n ex.name === \"UnknownError\" ||\n ex.message?.includes(\"not a known object store name\")\n ));\n const detail = isStorageBlocked\n ? \"Browser is blocking third-party storage. Please allow storage access or disable strict tracking protection.\"\n : \"Failed to access DPoP key from IndexedDB.\";\n targetWindow.postMessage({ type: \"error\", message: \"db failed\", detail }, openerOrigin);\n document.body.textContent = detail;\n throw ex;\n }\n\n const challenge = () => new Promise((resolve) => {\n const handler = (event) => {\n if (event.origin !== openerOrigin) return;\n if (event.data.type === \"challenge\") {\n resolve(event.data.challenge);\n window.removeEventListener(\"message\", handler);\n }\n };\n window.addEventListener(\"message\", handler, false);\n });\n\n const pre_challenge = challenge();\n\n targetWindow.postMessage({ type: \"pageLoaded\", message: \"yay\" }, openerOrigin);\n\n const challengeResp = await pre_challenge;\n if (typeof challengeResp !== \"string\" || challengeResp?.length != 64) throw Error(\"Unexpect challenge format\");\n\n const te = new TextEncoder();\n const signatureInput = te.encode(\"dpop-auth-challenge:\" + challengeResp);\n const algName = dpopKey.keys.privateKey.algorithm.name;\n const signParams = algName === \"ECDSA\"\n ? { name: \"ECDSA\", hash: { \"P-256\": \"SHA-256\", \"P-384\": \"SHA-384\", \"P-521\": \"SHA-512\" }[dpopKey.keys.privateKey.algorithm.namedCurve] }\n : { name: algName };\n const signature = await crypto.subtle.sign(signParams, dpopKey.keys.privateKey, signatureInput);\n\n const publicJwk = await crypto.subtle.exportKey(\"jwk\", dpopKey.keys.publicKey);\n\n targetWindow.postMessage({\n type: \"challenge response\",\n message: {\n dpop_public: JSON.stringify({ crv: publicJwk.crv, kty: publicJwk.kty, x: publicJwk.x, y: publicJwk.y }),\n signature: btoa(String.fromCharCode(...new Uint8Array(signature)))\n }\n }, openerOrigin);\n\n showSuccess();\n };\n\n const versionFlows = new Map([[1, version1Flow]]);\n const latestFlow = version1Flow;\n\n (async () => {\n if (Number(enclaveVersion) >= thisVersion) await latestFlow();\n else {\n const flow = versionFlows.get(Number(enclaveVersion));\n if (!flow) throw Error(\"Cannot find supported enclave version: \" + enclaveVersion);\n await flow();\n }\n })();\n </script>\n</body>\n\n</html>";
|
|
2
|
-
export declare const DPOP_AUTH_CSP = "default-src 'self'; script-src 'self' 'sha256-utc6UrebuHOyLd/2aiMXS/p1EDy9UZBDe/XEMKDw9Mc='; style-src 'self' 'sha256-F7OJTdJYct4J+cQfuJUoDauitndqt8pAc8EbA8gwDPU='";
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @deprecated The policy editor is no longer part of @tidecloak/js. This entry
|
|
3
|
-
* point is kept so existing imports still resolve; every component throws when
|
|
4
|
-
* rendered. The @tidecloak/policy package it used to re-export was never
|
|
5
|
-
* published to npm.
|
|
6
|
-
*/
|
|
7
|
-
export type Policy = any;
|
|
8
|
-
export type PolicyBlock = any;
|
|
9
|
-
export type Model = any;
|
|
10
|
-
export type ModelField = any;
|
|
11
|
-
export type Claim = any;
|
|
12
|
-
/** @typedef {any} Policy */
|
|
13
|
-
/** @typedef {any} PolicyBlock */
|
|
14
|
-
/** @typedef {any} Model */
|
|
15
|
-
/** @typedef {any} ModelField */
|
|
16
|
-
/** @typedef {any} Claim */
|
|
17
|
-
/**
|
|
18
|
-
* @deprecated The policy editor has moved out of @tidecloak/js.
|
|
19
|
-
* @param {any} _props
|
|
20
|
-
* @returns {never}
|
|
21
|
-
*/
|
|
22
|
-
export declare function PolicyBuilder(_props: any): never;
|
|
23
|
-
/**
|
|
24
|
-
* @deprecated The policy editor has moved out of @tidecloak/js.
|
|
25
|
-
* @param {any} _props
|
|
26
|
-
* @returns {never}
|
|
27
|
-
*/
|
|
28
|
-
export declare function PolicyCanvas(_props: any): never;
|
|
29
|
-
/**
|
|
30
|
-
* @deprecated The policy editor has moved out of @tidecloak/js.
|
|
31
|
-
* @param {any} _props
|
|
32
|
-
* @returns {never}
|
|
33
|
-
*/
|
|
34
|
-
export declare function PropertiesPanel(_props: any): never;
|
|
35
|
-
/**
|
|
36
|
-
* @deprecated The policy editor has moved out of @tidecloak/js.
|
|
37
|
-
* @param {any} _props
|
|
38
|
-
* @returns {never}
|
|
39
|
-
*/
|
|
40
|
-
export declare function BlockPalette(_props: any): never;
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Type definitions for @tidecloak/js native mode
|
|
3
|
-
*/
|
|
4
|
-
/**
|
|
5
|
-
* Token data for native mode storage.
|
|
6
|
-
*/
|
|
7
|
-
export interface NativeTokenData {
|
|
8
|
-
accessToken: string;
|
|
9
|
-
refreshToken: string;
|
|
10
|
-
idToken?: string;
|
|
11
|
-
/** Tide doken (delegated token) for encryption/decryption operations */
|
|
12
|
-
doken?: string;
|
|
13
|
-
expiresAt: number;
|
|
14
|
-
}
|
|
15
|
-
/**
|
|
16
|
-
* Auth callback result from native app.
|
|
17
|
-
*/
|
|
18
|
-
export interface NativeAuthCallbackResult {
|
|
19
|
-
code?: string;
|
|
20
|
-
error?: string;
|
|
21
|
-
errorDescription?: string;
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Native adapter interface for platform-specific operations.
|
|
25
|
-
*
|
|
26
|
-
* This is the MINIMAL interface developers must implement for their platform.
|
|
27
|
-
* The SDK handles everything else (encryption, token management, etc.).
|
|
28
|
-
*
|
|
29
|
-
* @example
|
|
30
|
-
* ```typescript
|
|
31
|
-
* // Electron example - minimal implementation
|
|
32
|
-
* const adapter: NativeAdapter = {
|
|
33
|
-
* getRedirectUri: () => 'myapp://auth/callback',
|
|
34
|
-
* openExternalUrl: (url) => shell.openExternal(url),
|
|
35
|
-
* onAuthCallback: (callback) => {
|
|
36
|
-
* ipcRenderer.on('auth-callback', (_, data) => callback(data));
|
|
37
|
-
* return () => ipcRenderer.off('auth-callback');
|
|
38
|
-
* },
|
|
39
|
-
* saveTokens: (tokens) => store.set('tokens', tokens),
|
|
40
|
-
* getTokens: () => store.get('tokens'),
|
|
41
|
-
* deleteTokens: () => store.delete('tokens'),
|
|
42
|
-
* };
|
|
43
|
-
* ```
|
|
44
|
-
*/
|
|
45
|
-
export interface NativeAdapter {
|
|
46
|
-
/** Get the redirect URI for this platform (can be async for dynamic URIs) */
|
|
47
|
-
getRedirectUri: () => string | Promise<string>;
|
|
48
|
-
/** Open a URL in the external browser or popup window */
|
|
49
|
-
openExternalUrl: (url: string) => Promise<void>;
|
|
50
|
-
/** Subscribe to auth callbacks - returns cleanup function */
|
|
51
|
-
onAuthCallback: (callback: (result: NativeAuthCallbackResult) => void) => () => void;
|
|
52
|
-
/** Store tokens securely on the device */
|
|
53
|
-
saveTokens: (tokens: NativeTokenData) => Promise<boolean>;
|
|
54
|
-
/** Retrieve stored tokens */
|
|
55
|
-
getTokens: () => Promise<NativeTokenData | null>;
|
|
56
|
-
/** Delete stored tokens (logout) */
|
|
57
|
-
deleteTokens: () => Promise<boolean>;
|
|
58
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
* Native mode configuration.
|
|
61
|
-
* All TideCloak configuration is here - the adapter only handles platform-specific operations.
|
|
62
|
-
*
|
|
63
|
-
* @example
|
|
64
|
-
* ```typescript
|
|
65
|
-
* import adapterConfig from './adapter.json';
|
|
66
|
-
*
|
|
67
|
-
* const config: NativeConfig = {
|
|
68
|
-
* authMode: 'native',
|
|
69
|
-
* adapter: myAdapter,
|
|
70
|
-
* // Spread the adapter.json config - it has all the TideCloak settings
|
|
71
|
-
* ...adapterConfig,
|
|
72
|
-
* };
|
|
73
|
-
* ```
|
|
74
|
-
*/
|
|
75
|
-
export interface NativeConfig {
|
|
76
|
-
/** Must be "native" for native mode */
|
|
77
|
-
authMode: "native";
|
|
78
|
-
/** Native adapter with platform-specific implementations */
|
|
79
|
-
adapter: NativeAdapter;
|
|
80
|
-
/** Auth server URL (e.g., "http://localhost:8080") */
|
|
81
|
-
"auth-server-url": string;
|
|
82
|
-
/** Realm name */
|
|
83
|
-
realm: string;
|
|
84
|
-
/** Client ID (resource in adapter.json) */
|
|
85
|
-
resource: string;
|
|
86
|
-
/** Tide vendor ID for encryption operations */
|
|
87
|
-
vendorId?: string;
|
|
88
|
-
/** Home ORK URL (e.g., "https://ork1.tideprotocol.com") */
|
|
89
|
-
homeOrkUrl?: string;
|
|
90
|
-
/**
|
|
91
|
-
* Client origin authentication signatures.
|
|
92
|
-
* These are keyed by origin (e.g., "client-origin-auth-http://localhost:5173").
|
|
93
|
-
* The SDK automatically selects the right one based on window.location.origin.
|
|
94
|
-
*/
|
|
95
|
-
[key: `client-origin-auth-${string}`]: string;
|
|
96
|
-
backgroundUrl: string;
|
|
97
|
-
logoUrl: string;
|
|
98
|
-
/** Session mode: 'online' (default) validates tokens, 'offline' accepts stored tokens */
|
|
99
|
-
sessionMode?: 'online' | 'offline';
|
|
100
|
-
/** OAuth scopes (defaults to "openid profile email") */
|
|
101
|
-
scope?: string;
|
|
102
|
-
/** JWK for token verification (from adapter.json) */
|
|
103
|
-
jwk?: {
|
|
104
|
-
keys: Array<{
|
|
105
|
-
kid: string;
|
|
106
|
-
kty: string;
|
|
107
|
-
alg: string;
|
|
108
|
-
use: string;
|
|
109
|
-
crv?: string;
|
|
110
|
-
x?: string;
|
|
111
|
-
[key: string]: unknown;
|
|
112
|
-
}>;
|
|
113
|
-
};
|
|
114
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
export declare function utf8ToHex(value: any): string;
|
|
2
|
-
export declare function buildDpopAuthUrl({ origin, authServerUrl, realm, clientId }: {
|
|
3
|
-
authServerUrl: any;
|
|
4
|
-
clientId: any;
|
|
5
|
-
origin: any;
|
|
6
|
-
realm: any;
|
|
7
|
-
}): string | null;
|
|
8
|
-
export declare function probeDpopAuthPage({ url, fetchImpl, timeoutMs }: {
|
|
9
|
-
fetchImpl?: typeof fetch | undefined;
|
|
10
|
-
timeoutMs?: number | undefined;
|
|
11
|
-
url: any;
|
|
12
|
-
}): Promise<{
|
|
13
|
-
outcome: string;
|
|
14
|
-
missing?: undefined;
|
|
15
|
-
} | {
|
|
16
|
-
outcome: string;
|
|
17
|
-
missing: string[];
|
|
18
|
-
}>;
|
|
19
|
-
export declare function preflightDpopAuthPage({ logger, ...params }: {
|
|
20
|
-
[x: string]: any;
|
|
21
|
-
logger?: Console | undefined;
|
|
22
|
-
}): Promise<string>;
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Fetch utilities for HTTP requests.
|
|
3
|
-
*/
|
|
4
|
-
/**
|
|
5
|
-
* Fetch JSON with credentials included.
|
|
6
|
-
* @param {string} url - URL to fetch
|
|
7
|
-
* @param {RequestInit} [options={}] - Fetch options
|
|
8
|
-
* @returns {Promise<any>} Parsed JSON response
|
|
9
|
-
* @throws {Error} If request fails (with status and body properties)
|
|
10
|
-
*/
|
|
11
|
-
export declare function fetchJson(url: string, options?: RequestInit): Promise<any>;
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
export { makePkce, randomPkceVerifier, base64UrlEncode } from './pkce.js';
|
|
2
|
-
export { fetchJson } from './fetch.js';
|
|
3
|
-
export { resolveSilentCheckSsoRedirectUri, SILENT_CHECK_SSO_FILENAME } from './silentCheckSso.js';
|
|
4
|
-
export { buildInitOptions } from './initOptions.js';
|
|
5
|
-
export { preflightDpopAuthPage } from './dpopAuthPage.js';
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Builds the options object handed to `TideCloak.init()` from a caller's
|
|
3
|
-
* resolved TideCloak config.
|
|
4
|
-
*
|
|
5
|
-
* ## Why this is an ALLOWLIST, deliberately
|
|
6
|
-
*
|
|
7
|
-
* `IAMService.initIAM` has always built these options as an allowlist: it reads
|
|
8
|
-
* a handful of keys off the config and drops everything else on the floor. The
|
|
9
|
-
* config object is NOT a `KeycloakInitOptions` bag - it is an adapter/config
|
|
10
|
-
* snapshot (`tidecloak.json` + Tide fields + app-level OIDC hints), and callers
|
|
11
|
-
* legitimately put keys in it that are meaningful to `IAMService` (or to their
|
|
12
|
-
* own code) but that must NOT be handed to `init()`.
|
|
13
|
-
*
|
|
14
|
-
* PR #91 widened this allowlist to also forward `redirectUri`,
|
|
15
|
-
* `silentCheckSsoFallback`, `silentCheckSsoTimeout`, `scope` and a
|
|
16
|
-
* caller-supplied `pkceMethod`, on the reasoning that "each is inert unless the
|
|
17
|
-
* caller sets it". That reasoning is wrong in one important direction: consumers
|
|
18
|
-
* had been shipping configs with these keys set for as long as the keys were
|
|
19
|
-
* being SWALLOWED, so their behaviour was pinned to the SDK's defaults, not to
|
|
20
|
-
* the value in their config. Forwarding them is therefore a silent behaviour
|
|
21
|
-
* change for every existing consumer - the exact opposite of inert.
|
|
22
|
-
*
|
|
23
|
-
* `scope` is the sharpest edge: forwarding it rewrites the authorization
|
|
24
|
-
* request's scope, which changes the audience/roles on the issued access token
|
|
25
|
-
* and can strip a consumer's admin-API access.
|
|
26
|
-
*
|
|
27
|
-
* So: forward ONLY what the SDK genuinely needs, and keep the previously
|
|
28
|
-
* defaulted behaviour byte-for-byte. Any option that a consumer should be able
|
|
29
|
-
* to set must be added here CONSCIOUSLY, with its prior default preserved.
|
|
30
|
-
*
|
|
31
|
-
* ### Forwarded
|
|
32
|
-
* - `setupRequestEnclave` - passed through from the `initIAM` argument.
|
|
33
|
-
* - `onLoad` - always `"check-sso"`. NOT taken from config: callers (e.g. the
|
|
34
|
-
* admin console) set `onLoad: "login-required"`, and honouring it would send
|
|
35
|
-
* `#processInit` down the full-redirect branch and never run silent check-sso
|
|
36
|
-
* at all. That is a separate product decision.
|
|
37
|
-
* - `silentCheckSsoRedirectUri` - the resolved URI (see ./silentCheckSso.js).
|
|
38
|
-
* This is the ONE option PR #91 needed to make caller-supplied, and it stays.
|
|
39
|
-
* `undefined` => TideCloak skips silent check-sso and falls back to an
|
|
40
|
-
* interactive login rather than emitting a URI that would 400.
|
|
41
|
-
* - `pkceMethod` - always `"S256"`, as it was before PR #91.
|
|
42
|
-
* - `useDPoP` / `checkLoginIframe` - the two options `initIAM` has always
|
|
43
|
-
* forwarded. `useDPoP` is forwarded ONLY when the caller actually set it, and
|
|
44
|
-
* VERBATIM. DPoP is opt-in: nothing upstream may default it on, because
|
|
45
|
-
* enabling it appends `dpop_jkt` to the authorization request and the realm
|
|
46
|
-
* then issues a `cnf.jkt`-BOUND token, which a plain-Bearer consumer cannot
|
|
47
|
-
* use (RFC 9449) - a bare `401` with no explanation. Pinned in
|
|
48
|
-
* test/bootstrapDpop.test.js.
|
|
49
|
-
*
|
|
50
|
-
* ### Deliberately NOT forwarded (regression-tested in test/initOptions.test.js)
|
|
51
|
-
* `scope`, `redirectUri`, `silentCheckSsoFallback`, `silentCheckSsoTimeout`.
|
|
52
|
-
* Consumers depend on the SDK's defaults for these. `redirectUri` in particular
|
|
53
|
-
* is still READ from config by `IAMService.doLogin` / `doLogout` and is used as
|
|
54
|
-
* a derivation source for `silentCheckSsoRedirectUri`, so a sub-path-hosted app
|
|
55
|
-
* still gets a correct login redirect - it just does not have `kc.redirectUri`
|
|
56
|
-
* overridden at init time.
|
|
57
|
-
*
|
|
58
|
-
* @param {Object} args
|
|
59
|
-
* @param {Object|null|undefined} args.config Resolved TideCloak config.
|
|
60
|
-
* @param {boolean} args.setupRequestEnclave
|
|
61
|
-
* @param {string|undefined} args.silentCheckSsoRedirectUri Resolved URI, or
|
|
62
|
-
* `undefined` when no correct URI could be derived.
|
|
63
|
-
* @returns {Object} Options for `TideCloak.init()`.
|
|
64
|
-
*/
|
|
65
|
-
export declare function buildInitOptions({ config, setupRequestEnclave, silentCheckSsoRedirectUri, }: {
|
|
66
|
-
config: Object | null | undefined;
|
|
67
|
-
setupRequestEnclave: boolean;
|
|
68
|
-
silentCheckSsoRedirectUri: string | undefined;
|
|
69
|
-
}): Object;
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* PKCE (Proof Key for Code Exchange) utilities for OAuth 2.0 authorization code flow.
|
|
3
|
-
*/
|
|
4
|
-
/**
|
|
5
|
-
* Generate random PKCE verifier string.
|
|
6
|
-
* @param {number} len - Length of the verifier (default 96)
|
|
7
|
-
* @returns {string} Random verifier string
|
|
8
|
-
*/
|
|
9
|
-
export declare function randomPkceVerifier(len?: number): string;
|
|
10
|
-
/**
|
|
11
|
-
* Base64 URL encode an ArrayBuffer.
|
|
12
|
-
* @param {ArrayBuffer} arrayBuffer - Buffer to encode
|
|
13
|
-
* @returns {string} Base64 URL encoded string
|
|
14
|
-
*/
|
|
15
|
-
export declare function base64UrlEncode(arrayBuffer: ArrayBuffer): string;
|
|
16
|
-
/**
|
|
17
|
-
* Generate PKCE verifier and challenge.
|
|
18
|
-
* @returns {Promise<{verifier: string, challenge: string, method: string}>}
|
|
19
|
-
*/
|
|
20
|
-
export declare function makePkce(): Promise<{
|
|
21
|
-
verifier: string;
|
|
22
|
-
challenge: string;
|
|
23
|
-
method: string;
|
|
24
|
-
}>;
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Resolution of the silent-check-SSO redirect URI.
|
|
3
|
-
*
|
|
4
|
-
* ## Why this exists
|
|
5
|
-
*
|
|
6
|
-
* `IAMService.initIAM` used to hardcode:
|
|
7
|
-
*
|
|
8
|
-
* ```js
|
|
9
|
-
* silentCheckSsoRedirectUri: `${window.location.origin}/silent-check-sso.html`
|
|
10
|
-
* ```
|
|
11
|
-
*
|
|
12
|
-
* That is only correct for an app served from the ORIGIN ROOT. For any app
|
|
13
|
-
* hosted under a sub-path (e.g. a console served at
|
|
14
|
-
* `https://host/realms/<realm>/tide-console/`) the origin-root URI is:
|
|
15
|
-
*
|
|
16
|
-
* - NOT served (there is no file at `/silent-check-sso.html`), and
|
|
17
|
-
* - NOT a registered `redirectUri` on the OIDC client,
|
|
18
|
-
*
|
|
19
|
-
* so the authorization request fails with `400 Invalid parameter: redirect_uri`.
|
|
20
|
-
* The silent iframe then never posts back and the app hangs on its bootstrap
|
|
21
|
-
* spinner. A silently-wrong URI is the worst possible outcome, so this module
|
|
22
|
-
* either derives a CORRECT base-aware URI or reports that it cannot, letting
|
|
23
|
-
* the caller fail loud and fall back to a redirect-based login.
|
|
24
|
-
*
|
|
25
|
-
* ## Resolution order
|
|
26
|
-
*
|
|
27
|
-
* 1. **Caller-supplied `silentCheckSsoRedirectUri`** - always wins, verbatim.
|
|
28
|
-
* 2. **`<base href>`** - the standard way a sub-path-hosted SPA declares where
|
|
29
|
-
* it lives. Resolved via the browser's own `document.baseURI`.
|
|
30
|
-
* 3. **The app's configured OIDC `redirectUri`** - the SDK already requires this
|
|
31
|
-
* to be base-aware and registered, so it is a sound source of truth for the
|
|
32
|
-
* app's base. The SDK's own convention is `<base>auth/redirect`, which is
|
|
33
|
-
* stripped to recover `<base>` exactly; any other redirect path is resolved
|
|
34
|
-
* relative to its own directory.
|
|
35
|
-
* 4. **Origin root** - only when the app declares NEITHER a base NOR a
|
|
36
|
-
* redirectUri. Such an app is relying on the SDK's origin-root default
|
|
37
|
-
* redirectUri (`${origin}/auth/redirect`) and is therefore root-hosted by
|
|
38
|
-
* construction. This preserves the historical behaviour for every existing
|
|
39
|
-
* root-hosted consumer.
|
|
40
|
-
*
|
|
41
|
-
* Anything that cannot be resolved (cross-origin or malformed redirectUri)
|
|
42
|
-
* returns `uri: undefined` plus a `reason`, so the caller can log an error and
|
|
43
|
-
* SKIP the silent check rather than emit a URI that will 400.
|
|
44
|
-
*/
|
|
45
|
-
/** Filename the SDK ships and that hosting providers are expected to serve. */
|
|
46
|
-
export declare const SILENT_CHECK_SSO_FILENAME = "silent-check-sso.html";
|
|
47
|
-
export type SilentCheckSsoResolution = {
|
|
48
|
-
/**
|
|
49
|
-
* The resolved URI, or undefined if none could be derived.
|
|
50
|
-
*/
|
|
51
|
-
uri: string | undefined;
|
|
52
|
-
source: 'config' | 'base-href' | 'redirect-uri-convention' | 'redirect-uri' | 'origin-root' | 'none';
|
|
53
|
-
/**
|
|
54
|
-
* Why resolution failed (only when `uri` is undefined).
|
|
55
|
-
*/
|
|
56
|
-
reason?: string;
|
|
57
|
-
};
|
|
58
|
-
/**
|
|
59
|
-
* @typedef {object} SilentCheckSsoResolution
|
|
60
|
-
* @property {string|undefined} uri The resolved URI, or undefined if none could be derived.
|
|
61
|
-
* @property {'config'|'base-href'|'redirect-uri-convention'|'redirect-uri'|'origin-root'|'none'} source
|
|
62
|
-
* @property {string} [reason] Why resolution failed (only when `uri` is undefined).
|
|
63
|
-
*/
|
|
64
|
-
/**
|
|
65
|
-
* Resolve the silent-check-SSO redirect URI.
|
|
66
|
-
*
|
|
67
|
-
* Pure: every environment input is passed in explicitly, so this is unit-testable
|
|
68
|
-
* with no DOM. See the module docblock for the resolution order.
|
|
69
|
-
*
|
|
70
|
-
* @param {object} params
|
|
71
|
-
* @param {string} params.origin The app's origin (`window.location.origin`).
|
|
72
|
-
* @param {string} [params.configured] Caller-supplied `silentCheckSsoRedirectUri`.
|
|
73
|
-
* @param {string} [params.baseHref] `document.baseURI`, but ONLY when a `<base href>` element exists.
|
|
74
|
-
* @param {string} [params.redirectUri] Caller-supplied OIDC `redirectUri`.
|
|
75
|
-
* @returns {SilentCheckSsoResolution}
|
|
76
|
-
*/
|
|
77
|
-
export declare function resolveSilentCheckSsoRedirectUri({ origin, configured, baseHref, redirectUri }?: {
|
|
78
|
-
origin: string;
|
|
79
|
-
configured?: string;
|
|
80
|
-
baseHref?: string;
|
|
81
|
-
redirectUri?: string;
|
|
82
|
-
}): SilentCheckSsoResolution;
|
package/dist/types/src/vite.d.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @param {Object} [options]
|
|
3
|
-
* @param {Object} [options.config] TideCloak adapter config (tidecloak.json). Used to
|
|
4
|
-
* reject requests for another realm or client.
|
|
5
|
-
*/
|
|
6
|
-
export declare function tideDpopPlugin({ config }?: {
|
|
7
|
-
config?: Object;
|
|
8
|
-
}): {
|
|
9
|
-
name: string;
|
|
10
|
-
configureServer: (server: any) => void;
|
|
11
|
-
configurePreviewServer: (server: any) => void;
|
|
12
|
-
};
|
|
13
|
-
export default tideDpopPlugin;
|
package/dist/types/types.d.ts
DELETED
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Type definitions for @tidecloak/js native mode
|
|
3
|
-
*/
|
|
4
|
-
/**
|
|
5
|
-
* Token data for native mode storage.
|
|
6
|
-
*/
|
|
7
|
-
export interface NativeTokenData {
|
|
8
|
-
accessToken: string;
|
|
9
|
-
refreshToken: string;
|
|
10
|
-
idToken?: string;
|
|
11
|
-
/** Tide doken (delegated token) for encryption/decryption operations */
|
|
12
|
-
doken?: string;
|
|
13
|
-
expiresAt: number;
|
|
14
|
-
}
|
|
15
|
-
/**
|
|
16
|
-
* Auth callback result from native app.
|
|
17
|
-
*/
|
|
18
|
-
export interface NativeAuthCallbackResult {
|
|
19
|
-
code?: string;
|
|
20
|
-
error?: string;
|
|
21
|
-
errorDescription?: string;
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Native adapter interface for platform-specific operations.
|
|
25
|
-
*
|
|
26
|
-
* This is the MINIMAL interface developers must implement for their platform.
|
|
27
|
-
* The SDK handles everything else (encryption, token management, etc.).
|
|
28
|
-
*
|
|
29
|
-
* @example
|
|
30
|
-
* ```typescript
|
|
31
|
-
* // Electron example - minimal implementation
|
|
32
|
-
* const adapter: NativeAdapter = {
|
|
33
|
-
* getRedirectUri: () => 'myapp://auth/callback',
|
|
34
|
-
* openExternalUrl: (url) => shell.openExternal(url),
|
|
35
|
-
* onAuthCallback: (callback) => {
|
|
36
|
-
* ipcRenderer.on('auth-callback', (_, data) => callback(data));
|
|
37
|
-
* return () => ipcRenderer.off('auth-callback');
|
|
38
|
-
* },
|
|
39
|
-
* saveTokens: (tokens) => store.set('tokens', tokens),
|
|
40
|
-
* getTokens: () => store.get('tokens'),
|
|
41
|
-
* deleteTokens: () => store.delete('tokens'),
|
|
42
|
-
* };
|
|
43
|
-
* ```
|
|
44
|
-
*/
|
|
45
|
-
export interface NativeAdapter {
|
|
46
|
-
/** Get the redirect URI for this platform (can be async for dynamic URIs) */
|
|
47
|
-
getRedirectUri: () => string | Promise<string>;
|
|
48
|
-
/** Open a URL in the external browser or popup window */
|
|
49
|
-
openExternalUrl: (url: string) => Promise<void>;
|
|
50
|
-
/** Subscribe to auth callbacks - returns cleanup function */
|
|
51
|
-
onAuthCallback: (callback: (result: NativeAuthCallbackResult) => void) => () => void;
|
|
52
|
-
/** Store tokens securely on the device */
|
|
53
|
-
saveTokens: (tokens: NativeTokenData) => Promise<boolean>;
|
|
54
|
-
/** Retrieve stored tokens */
|
|
55
|
-
getTokens: () => Promise<NativeTokenData | null>;
|
|
56
|
-
/** Delete stored tokens (logout) */
|
|
57
|
-
deleteTokens: () => Promise<boolean>;
|
|
58
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
* Native mode configuration.
|
|
61
|
-
* All TideCloak configuration is here - the adapter only handles platform-specific operations.
|
|
62
|
-
*
|
|
63
|
-
* @example
|
|
64
|
-
* ```typescript
|
|
65
|
-
* import adapterConfig from './adapter.json';
|
|
66
|
-
*
|
|
67
|
-
* const config: NativeConfig = {
|
|
68
|
-
* authMode: 'native',
|
|
69
|
-
* adapter: myAdapter,
|
|
70
|
-
* // Spread the adapter.json config - it has all the TideCloak settings
|
|
71
|
-
* ...adapterConfig,
|
|
72
|
-
* };
|
|
73
|
-
* ```
|
|
74
|
-
*/
|
|
75
|
-
export interface NativeConfig {
|
|
76
|
-
/** Must be "native" for native mode */
|
|
77
|
-
authMode: "native";
|
|
78
|
-
/** Native adapter with platform-specific implementations */
|
|
79
|
-
adapter: NativeAdapter;
|
|
80
|
-
/** Auth server URL (e.g., "http://localhost:8080") */
|
|
81
|
-
"auth-server-url": string;
|
|
82
|
-
/** Realm name */
|
|
83
|
-
realm: string;
|
|
84
|
-
/** Client ID (resource in adapter.json) */
|
|
85
|
-
resource: string;
|
|
86
|
-
/** Tide vendor ID for encryption operations */
|
|
87
|
-
vendorId?: string;
|
|
88
|
-
/** Home ORK URL (e.g., "https://ork1.tideprotocol.com") */
|
|
89
|
-
homeOrkUrl?: string;
|
|
90
|
-
/**
|
|
91
|
-
* Client origin authentication signatures.
|
|
92
|
-
* These are keyed by origin (e.g., "client-origin-auth-http://localhost:5173").
|
|
93
|
-
* The SDK automatically selects the right one based on window.location.origin.
|
|
94
|
-
*/
|
|
95
|
-
[key: `client-origin-auth-${string}`]: string;
|
|
96
|
-
backgroundUrl: string;
|
|
97
|
-
logoUrl: string;
|
|
98
|
-
/** Session mode: 'online' (default) validates tokens, 'offline' accepts stored tokens */
|
|
99
|
-
sessionMode?: 'online' | 'offline';
|
|
100
|
-
/** OAuth scopes (defaults to "openid profile email") */
|
|
101
|
-
scope?: string;
|
|
102
|
-
/** JWK for token verification (from adapter.json) */
|
|
103
|
-
jwk?: {
|
|
104
|
-
keys: Array<{
|
|
105
|
-
kid: string;
|
|
106
|
-
kty: string;
|
|
107
|
-
alg: string;
|
|
108
|
-
use: string;
|
|
109
|
-
crv?: string;
|
|
110
|
-
x?: string;
|
|
111
|
-
[key: string]: unknown;
|
|
112
|
-
}>;
|
|
113
|
-
};
|
|
114
|
-
}
|