@strivacity/sdk-core 3.0.2 → 4.0.0-beta.0
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/CHANGELOG.md +11 -0
- package/README.md +1873 -340
- package/dist/assets/oidc.cjs +2 -0
- package/dist/assets/oidc.cjs.map +1 -0
- package/dist/assets/oidc.mjs +2 -0
- package/dist/assets/oidc.mjs.map +1 -0
- package/dist/assets/server.cjs +2 -0
- package/dist/assets/server.cjs.map +1 -0
- package/dist/assets/server.mjs +2 -0
- package/dist/assets/server.mjs.map +1 -0
- package/dist/flows/base.cjs +2 -0
- package/dist/flows/base.cjs.map +1 -0
- package/dist/flows/base.d.ts +26 -0
- package/dist/flows/base.mjs +2 -0
- package/dist/flows/base.mjs.map +1 -0
- package/dist/flows/embedded.cjs +2 -0
- package/dist/flows/embedded.cjs.map +1 -0
- package/dist/flows/embedded.d.ts +9 -0
- package/dist/flows/embedded.mjs +2 -0
- package/dist/flows/embedded.mjs.map +1 -0
- package/dist/flows/index.cjs +1 -0
- package/dist/flows/index.d.ts +5 -0
- package/dist/flows/index.mjs +1 -0
- package/dist/flows/native.cjs +2 -0
- package/dist/flows/native.cjs.map +1 -0
- package/dist/flows/native.d.ts +9 -0
- package/dist/flows/native.mjs +2 -0
- package/dist/flows/native.mjs.map +1 -0
- package/dist/flows/popup.cjs +2 -0
- package/dist/flows/popup.cjs.map +1 -0
- package/dist/flows/popup.d.ts +9 -0
- package/dist/flows/popup.mjs +2 -0
- package/dist/flows/popup.mjs.map +1 -0
- package/dist/flows/redirect.cjs +2 -0
- package/dist/flows/redirect.cjs.map +1 -0
- package/dist/flows/redirect.d.ts +9 -0
- package/dist/flows/redirect.mjs +2 -0
- package/dist/flows/redirect.mjs.map +1 -0
- package/dist/handlers/embedded.cjs +2 -0
- package/dist/handlers/embedded.cjs.map +1 -0
- package/dist/handlers/embedded.d.ts +37 -0
- package/dist/handlers/embedded.mjs +2 -0
- package/dist/handlers/embedded.mjs.map +1 -0
- package/dist/handlers/index.cjs +1 -0
- package/dist/handlers/index.d.ts +2 -0
- package/dist/handlers/index.mjs +1 -0
- package/dist/handlers/native.cjs +2 -0
- package/dist/handlers/native.cjs.map +1 -0
- package/dist/handlers/native.d.ts +56 -0
- package/dist/handlers/native.mjs +2 -0
- package/dist/handlers/native.mjs.map +1 -0
- package/dist/handlers/popup.cjs +2 -0
- package/dist/handlers/popup.cjs.map +1 -0
- package/dist/handlers/popup.d.ts +21 -0
- package/dist/handlers/popup.mjs +2 -0
- package/dist/handlers/popup.mjs.map +1 -0
- package/dist/handlers/redirect.cjs +2 -0
- package/dist/handlers/redirect.cjs.map +1 -0
- package/dist/handlers/redirect.d.ts +18 -0
- package/dist/handlers/redirect.mjs +2 -0
- package/dist/handlers/redirect.mjs.map +1 -0
- package/dist/index.cjs +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +16 -21
- package/dist/index.mjs +2 -2
- package/dist/index.mjs.map +1 -1
- package/dist/server/base.cjs +2 -0
- package/dist/server/base.cjs.map +1 -0
- package/dist/server/base.d.ts +15 -0
- package/dist/server/base.mjs +2 -0
- package/dist/server/base.mjs.map +1 -0
- package/dist/server/index.cjs +1 -0
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.mjs +1 -0
- package/dist/storages/cache.cjs +2 -0
- package/dist/storages/cache.cjs.map +1 -0
- package/dist/storages/cache.d.ts +11 -0
- package/dist/storages/cache.mjs +2 -0
- package/dist/storages/cache.mjs.map +1 -0
- package/dist/storages/index.cjs +1 -0
- package/dist/storages/index.d.ts +7 -0
- package/dist/storages/index.mjs +1 -0
- package/dist/storages/indexeddb.cjs +2 -0
- package/dist/storages/indexeddb.cjs.map +1 -0
- package/dist/storages/indexeddb.d.ts +10 -0
- package/dist/storages/indexeddb.mjs +2 -0
- package/dist/storages/indexeddb.mjs.map +1 -0
- package/dist/storages/local.cjs +2 -0
- package/dist/storages/local.cjs.map +1 -0
- package/dist/storages/local.d.ts +7 -0
- package/dist/storages/local.mjs +2 -0
- package/dist/storages/local.mjs.map +1 -0
- package/dist/storages/memory.cjs +2 -0
- package/dist/storages/memory.cjs.map +1 -0
- package/dist/storages/memory.d.ts +8 -0
- package/dist/storages/memory.mjs +2 -0
- package/dist/storages/memory.mjs.map +1 -0
- package/dist/storages/server.cjs +1 -0
- package/dist/storages/server.d.ts +39 -0
- package/dist/storages/server.mjs +1 -0
- package/dist/storages/session.cjs +2 -0
- package/dist/storages/session.cjs.map +1 -0
- package/dist/storages/session.d.ts +7 -0
- package/dist/storages/session.mjs +2 -0
- package/dist/storages/session.mjs.map +1 -0
- package/dist/storages/worker.cjs +2 -0
- package/dist/storages/worker.cjs.map +1 -0
- package/dist/storages/worker.d.ts +46 -0
- package/dist/storages/worker.mjs +2 -0
- package/dist/storages/worker.mjs.map +1 -0
- package/dist/types/common.cjs +0 -0
- package/dist/types/common.d.ts +145 -0
- package/dist/types/common.mjs +0 -0
- package/dist/types/embedded.cjs +0 -0
- package/dist/types/embedded.d.ts +103 -0
- package/dist/types/embedded.mjs +0 -0
- package/dist/types/index.cjs +1 -0
- package/dist/types/index.d.ts +7 -0
- package/dist/types/index.mjs +1 -0
- package/dist/types/native.cjs +0 -0
- package/dist/types/native.d.ts +385 -0
- package/dist/types/native.mjs +0 -0
- package/dist/types/oidc.cjs +2 -0
- package/dist/types/oidc.cjs.map +1 -0
- package/dist/types/oidc.d.ts +768 -0
- package/dist/types/oidc.mjs +2 -0
- package/dist/types/oidc.mjs.map +1 -0
- package/dist/types/popup.cjs +0 -0
- package/dist/types/popup.d.ts +69 -0
- package/dist/types/popup.mjs +0 -0
- package/dist/types/redirect.cjs +0 -0
- package/dist/types/redirect.d.ts +21 -0
- package/dist/types/redirect.mjs +0 -0
- package/dist/types/server.cjs +0 -0
- package/dist/types/server.d.ts +200 -0
- package/dist/types/server.mjs +0 -0
- package/dist/utils/base64url.cjs +2 -0
- package/dist/utils/base64url.cjs.map +1 -0
- package/dist/utils/base64url.d.ts +14 -0
- package/dist/utils/base64url.mjs +2 -0
- package/dist/utils/base64url.mjs.map +1 -0
- package/dist/utils/common.cjs +2 -0
- package/dist/utils/common.cjs.map +1 -0
- package/dist/utils/common.d.ts +23 -0
- package/dist/utils/common.mjs +2 -0
- package/dist/utils/common.mjs.map +1 -0
- package/dist/utils/credentials.cjs +2 -2
- package/dist/utils/credentials.cjs.map +1 -1
- package/dist/utils/credentials.d.ts +19 -3
- package/dist/utils/credentials.mjs +2 -2
- package/dist/utils/credentials.mjs.map +1 -1
- package/dist/utils/crypto.cjs +2 -2
- package/dist/utils/crypto.cjs.map +1 -1
- package/dist/utils/crypto.d.ts +16 -26
- package/dist/utils/crypto.mjs +2 -2
- package/dist/utils/crypto.mjs.map +1 -1
- package/dist/utils/dom.cjs +2 -0
- package/dist/utils/dom.cjs.map +1 -0
- package/dist/utils/dom.d.ts +7 -0
- package/dist/utils/dom.mjs +2 -0
- package/dist/utils/dom.mjs.map +1 -0
- package/dist/utils/errors.cjs +2 -2
- package/dist/utils/errors.cjs.map +1 -1
- package/dist/utils/errors.d.ts +62 -1
- package/dist/utils/errors.mjs +2 -2
- package/dist/utils/errors.mjs.map +1 -1
- package/dist/utils/httpClient.cjs +2 -0
- package/dist/utils/httpClient.cjs.map +1 -0
- package/dist/utils/httpClient.d.ts +2 -0
- package/dist/utils/httpClient.mjs +2 -0
- package/dist/utils/httpClient.mjs.map +1 -0
- package/dist/utils/index.cjs +1 -0
- package/dist/utils/index.d.ts +12 -0
- package/dist/utils/index.mjs +1 -0
- package/dist/utils/logging.cjs +2 -0
- package/dist/utils/logging.cjs.map +1 -0
- package/dist/utils/logging.d.ts +2 -0
- package/dist/utils/logging.mjs +2 -0
- package/dist/utils/logging.mjs.map +1 -0
- package/dist/utils/oidc.cjs +1 -0
- package/dist/utils/oidc.d.ts +264 -0
- package/dist/utils/oidc.mjs +1 -0
- package/dist/utils/server.cjs +1 -0
- package/dist/utils/server.d.ts +72 -0
- package/dist/utils/server.mjs +1 -0
- package/dist/utils/session.cjs +2 -0
- package/dist/utils/session.cjs.map +1 -0
- package/dist/utils/session.d.ts +29 -0
- package/dist/utils/session.mjs +2 -0
- package/dist/utils/session.mjs.map +1 -0
- package/dist/utils/state.cjs +1 -0
- package/dist/utils/state.d.ts +23 -0
- package/dist/utils/state.mjs +1 -0
- package/package.json +53 -1
- package/testing/tests/flows/base.spec.ts +1030 -0
- package/testing/tests/flows/embedded.spec.ts +443 -0
- package/testing/tests/flows/index.spec.ts +8 -0
- package/testing/tests/flows/native.spec.ts +487 -0
- package/testing/tests/flows/popup.spec.ts +400 -0
- package/testing/tests/flows/redirect.spec.ts +369 -0
- package/testing/tests/handlers/embedded.spec.ts +199 -0
- package/testing/tests/handlers/index.spec.ts +8 -0
- package/testing/tests/handlers/native.spec.ts +283 -0
- package/testing/tests/handlers/popup.spec.ts +206 -0
- package/testing/tests/handlers/redirect.spec.ts +70 -0
- package/testing/tests/index.spec.ts +78 -0
- package/testing/tests/server/base.spec.ts +846 -0
- package/testing/tests/server/index.spec.ts +15 -0
- package/testing/tests/storages/cache.spec.ts +107 -0
- package/testing/tests/storages/index.spec.ts +22 -0
- package/testing/tests/storages/indexeddb.spec.ts +113 -0
- package/testing/tests/storages/local.spec.ts +46 -0
- package/testing/tests/storages/memory.spec.ts +51 -0
- package/testing/tests/storages/server.spec.ts +435 -0
- package/testing/tests/storages/session.spec.ts +46 -0
- package/testing/tests/storages/worker.spec.ts +106 -0
- package/testing/tests/utils/common.spec.ts +77 -0
- package/testing/tests/utils/credentials.spec.ts +195 -0
- package/testing/tests/utils/dom.spec.ts +37 -0
- package/testing/tests/utils/index.spec.ts +71 -0
- package/testing/tests/utils/logging.spec.ts +82 -0
- package/testing/tests/utils/oidc.spec.ts +744 -0
- package/testing/tests/utils/server.spec.ts +235 -0
- package/dist/flows/BaseFlow.cjs +0 -2
- package/dist/flows/BaseFlow.cjs.map +0 -1
- package/dist/flows/BaseFlow.d.ts +0 -191
- package/dist/flows/BaseFlow.mjs +0 -2
- package/dist/flows/BaseFlow.mjs.map +0 -1
- package/dist/flows/EmbeddedFlow.cjs +0 -2
- package/dist/flows/EmbeddedFlow.cjs.map +0 -1
- package/dist/flows/EmbeddedFlow.d.ts +0 -26
- package/dist/flows/EmbeddedFlow.mjs +0 -2
- package/dist/flows/EmbeddedFlow.mjs.map +0 -1
- package/dist/flows/NativeFlow.cjs +0 -2
- package/dist/flows/NativeFlow.cjs.map +0 -1
- package/dist/flows/NativeFlow.d.ts +0 -34
- package/dist/flows/NativeFlow.mjs +0 -2
- package/dist/flows/NativeFlow.mjs.map +0 -1
- package/dist/flows/PopupFlow.cjs +0 -2
- package/dist/flows/PopupFlow.cjs.map +0 -1
- package/dist/flows/PopupFlow.d.ts +0 -36
- package/dist/flows/PopupFlow.mjs +0 -2
- package/dist/flows/PopupFlow.mjs.map +0 -1
- package/dist/flows/RedirectFlow.cjs +0 -2
- package/dist/flows/RedirectFlow.cjs.map +0 -1
- package/dist/flows/RedirectFlow.d.ts +0 -38
- package/dist/flows/RedirectFlow.mjs +0 -2
- package/dist/flows/RedirectFlow.mjs.map +0 -1
- package/dist/handlers/BaseFlowHandler.cjs +0 -2
- package/dist/handlers/BaseFlowHandler.cjs.map +0 -1
- package/dist/handlers/BaseFlowHandler.d.ts +0 -61
- package/dist/handlers/BaseFlowHandler.mjs +0 -2
- package/dist/handlers/BaseFlowHandler.mjs.map +0 -1
- package/dist/handlers/EmbeddedFlowHandler.cjs +0 -2
- package/dist/handlers/EmbeddedFlowHandler.cjs.map +0 -1
- package/dist/handlers/EmbeddedFlowHandler.d.ts +0 -28
- package/dist/handlers/EmbeddedFlowHandler.mjs +0 -2
- package/dist/handlers/EmbeddedFlowHandler.mjs.map +0 -1
- package/dist/handlers/NativeFlowHandler.cjs +0 -2
- package/dist/handlers/NativeFlowHandler.cjs.map +0 -1
- package/dist/handlers/NativeFlowHandler.d.ts +0 -31
- package/dist/handlers/NativeFlowHandler.mjs +0 -2
- package/dist/handlers/NativeFlowHandler.mjs.map +0 -1
- package/dist/storages/LocalStorage.cjs +0 -2
- package/dist/storages/LocalStorage.cjs.map +0 -1
- package/dist/storages/LocalStorage.d.ts +0 -23
- package/dist/storages/LocalStorage.mjs +0 -2
- package/dist/storages/LocalStorage.mjs.map +0 -1
- package/dist/storages/SessionStorage.cjs +0 -2
- package/dist/storages/SessionStorage.cjs.map +0 -1
- package/dist/storages/SessionStorage.d.ts +0 -23
- package/dist/storages/SessionStorage.mjs +0 -2
- package/dist/storages/SessionStorage.mjs.map +0 -1
- package/dist/types.cjs +0 -2
- package/dist/types.cjs.map +0 -1
- package/dist/types.d.ts +0 -1263
- package/dist/types.mjs +0 -2
- package/dist/types.mjs.map +0 -1
- package/dist/utils/HttpClient.cjs +0 -2
- package/dist/utils/HttpClient.cjs.map +0 -1
- package/dist/utils/HttpClient.d.ts +0 -4
- package/dist/utils/HttpClient.mjs +0 -2
- package/dist/utils/HttpClient.mjs.map +0 -1
- package/dist/utils/Logging.cjs +0 -2
- package/dist/utils/Logging.cjs.map +0 -1
- package/dist/utils/Logging.d.ts +0 -8
- package/dist/utils/Logging.mjs +0 -2
- package/dist/utils/Logging.mjs.map +0 -1
- package/dist/utils/Metadata.cjs +0 -2
- package/dist/utils/Metadata.cjs.map +0 -1
- package/dist/utils/Metadata.d.ts +0 -98
- package/dist/utils/Metadata.mjs +0 -2
- package/dist/utils/Metadata.mjs.map +0 -1
- package/dist/utils/Session.cjs +0 -2
- package/dist/utils/Session.cjs.map +0 -1
- package/dist/utils/Session.d.ts +0 -82
- package/dist/utils/Session.mjs +0 -2
- package/dist/utils/Session.mjs.map +0 -1
- package/dist/utils/State.cjs +0 -2
- package/dist/utils/State.cjs.map +0 -1
- package/dist/utils/State.d.ts +0 -43
- package/dist/utils/State.mjs +0 -2
- package/dist/utils/State.mjs.map +0 -1
- package/dist/utils/base64Url.cjs +0 -2
- package/dist/utils/base64Url.cjs.map +0 -1
- package/dist/utils/base64Url.d.ts +0 -27
- package/dist/utils/base64Url.mjs +0 -2
- package/dist/utils/base64Url.mjs.map +0 -1
- package/dist/utils/date.cjs +0 -2
- package/dist/utils/date.cjs.map +0 -1
- package/dist/utils/date.d.ts +0 -6
- package/dist/utils/date.mjs +0 -2
- package/dist/utils/date.mjs.map +0 -1
- package/dist/utils/handlers.cjs +0 -2
- package/dist/utils/handlers.cjs.map +0 -1
- package/dist/utils/handlers.d.ts +0 -35
- package/dist/utils/handlers.mjs +0 -2
- package/dist/utils/handlers.mjs.map +0 -1
- package/dist/utils/jwt.cjs +0 -2
- package/dist/utils/jwt.cjs.map +0 -1
- package/dist/utils/jwt.d.ts +0 -34
- package/dist/utils/jwt.mjs +0 -2
- package/dist/utils/jwt.mjs.map +0 -1
- package/dist/utils/object.cjs +0 -2
- package/dist/utils/object.cjs.map +0 -1
- package/dist/utils/object.d.ts +0 -1
- package/dist/utils/object.mjs +0 -2
- package/dist/utils/object.mjs.map +0 -1
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=require("../utils/errors.cjs"),t=require("../utils/base64url.cjs"),n=require("../utils/httpClient.cjs"),r=require("../utils/common.cjs"),i=require("../utils/session.cjs"),a=require("../handlers/redirect.cjs"),o=require("../storages/local.cjs"),s=require("../storages/session.cjs");async function c(e={}){let t=b();return{id:S(16),createdAt:r.timestamp(),codeVerifier:t,metadata:e,codeChallenge:await x(t),nonce:S(16)}}function l(e){return JSON.parse(e)}function u(e){return JSON.stringify(e)}var d=0,f=null,p=null,m=new Map;function h(){return{initialized:!1,session:null,sessionId:null,shortAppId:null,language:globalThis.navigator?.language??`en-US`}}var g={lazyLoad:!1,autoRefresh:!0,serverSessionUri:null,scopes:[`openid`],responseType:`code`,responseMode:`query`,storageTokenName:`sty.session`,discoveryDocumentCacheTTL:3600,jwksCacheTTL:600};async function _(t){return p&&d>r.timestamp()?p:f||(f=(async()=>{try{let n=await t.httpClient.request(new URL(`/.well-known/openid-configuration`,t.issuer));if(!n.ok)throw new e.ServerError(`Failed to fetch OIDC metadata`,n.status);let i;try{i=await n.json()}catch{throw new e.ProtocolError(`Non-JSON response from discovery document endpoint`)}if(i.issuer?.replace(/\/$/,``)!==t.issuer.replace(/\/$/,``))throw new e.ProtocolError(`Discovery document issuer mismatch: expected ${t.issuer}, got ${i.issuer}`);let a=new URL(t.issuer).host;for(let t of[`authorization_endpoint`,`token_endpoint`,`jwks_uri`]){let n=i[t];if(!n)throw new e.ProtocolError(`Discovery document is missing required field: ${t}`);let r=new URL(n);if(r.protocol!==`https:`||r.host!==a)throw new e.ProtocolError(`Discovery document field "${t}" must be an https:// URL on ${a}, got ${n}`)}for(let t of[`end_session_endpoint`,`revocation_endpoint`]){let n=i[t];if(!n)continue;let r=new URL(n);if(r.protocol!==`https:`||r.host!==a)throw new e.ProtocolError(`Discovery document field "${t}" must be an https:// URL on ${a}, got ${n}`)}if(!i.code_challenge_methods_supported?.includes(`S256`))throw new e.ProtocolError(`Discovery document does not advertise S256 PKCE support`);return p=i,d=r.timestamp()+t.discoveryDocumentCacheTTL,i}finally{f=null}})(),f)}async function v({jwksUri:t,options:n,forceRefresh:i=!1}){let a=m.get(t);if(!i&&a&&a.expiresAt>r.timestamp())return{keys:a.keys};let o;try{o=await fetch(t)}catch{throw new e.NetworkError(`Failed to fetch JWKS: ${t}`)}if(!o.ok)throw new e.ServerError(`Failed to fetch JWKS: HTTP ${o.status}`,o.status);let s=await o.json();return m.set(t,{keys:s.keys,expiresAt:r.timestamp()+n.jwksCacheTTL}),s}function y(e){return e.issuer=e.issuer.endsWith(`/`)?e.issuer.slice(0,-1):e.issuer,e.storage??=o.createLocalStorage(),e.stateStorage??=s.createSessionStorage(),e.httpClient??=n.createHttpClient(e.logging),e.urlHandler??=a.redirectUrlHandler,e.callbackHandler??=a.redirectCallbackHandler,e.lazyLoad??=g.lazyLoad,e.autoRefresh??=g.autoRefresh,e.serverSessionUri??=g.serverSessionUri,e.scopes??=g.scopes,e.responseType??=g.responseType,e.responseMode??=g.responseMode,e.storageTokenName??=g.storageTokenName,e.discoveryDocumentCacheTTL??=g.discoveryDocumentCacheTTL,e.jwksCacheTTL??=g.jwksCacheTTL,e}function b(){let e=new Uint8Array(32);return globalThis.crypto.getRandomValues(e),t.encodeBase64URL(e.buffer)}async function x(e){let n=new TextEncoder().encode(e),r=await globalThis.crypto.subtle.digest(`SHA-256`,n);return t.encodeBase64URL(r)}function S(e=16){let t=new Uint8Array(e);return globalThis.crypto.getRandomValues(t),Array.from(t).map(e=>e.toString(16).padStart(2,`0`)).join(``)}function C(n){let[,r]=n.split(`.`);if(!r)throw new e.ProtocolError(`Invalid JWT: missing payload segment`);try{return JSON.parse(new TextDecoder().decode(t.decodeBase64URL(r)))}catch{throw new e.ProtocolError(`Invalid JWT: payload is not valid base64url-encoded JSON`)}}async function w({token:n,jwksUri:r,options:i}){let a=n.split(`.`);if(a.length!==3)throw new e.ProtocolError(`Invalid JWT: must have 3 parts`);let[o,s,c]=a,l=JSON.parse(new TextDecoder().decode(t.decodeBase64URL(o)));if(l.alg!==`RS256`)throw new e.ProtocolError(`Unsupported JWT algorithm: ${l.alg}`);let u=await v({jwksUri:r,options:i}),d=l.kid?u.keys.find(e=>e.kid===l.kid):u.keys.find(e=>e.alg===`RS256`);if(!d&&l.kid&&(u=await v({jwksUri:r,options:i,forceRefresh:!0}),d=u.keys.find(e=>e.kid===l.kid)),!d)throw new e.ProtocolError(`No matching key found in JWKS${l.kid?` for kid: ${l.kid}`:``}`);let f=await globalThis.crypto.subtle.importKey(`jwk`,{kty:d.kty,n:d.n,e:d.e,alg:d.alg,use:d.use},{name:`RSASSA-PKCS1-v1_5`,hash:{name:`SHA-256`}},!1,[`verify`]),p=t.decodeBase64URL(c),m=new TextEncoder().encode(`${o}.${s}`);if(!await globalThis.crypto.subtle.verify({name:`RSASSA-PKCS1-v1_5`},f,p,m))throw new e.ProtocolError(`JWT signature verification failed`);return JSON.parse(new TextDecoder().decode(t.decodeBase64URL(s)))}async function T(e,n,r){let i=`${t.encodeBase64URL(new TextEncoder().encode(JSON.stringify(e)).buffer)}.${t.encodeBase64URL(new TextEncoder().encode(JSON.stringify(n)).buffer)}`;if(r){let e=await globalThis.crypto.subtle.sign({name:`ECDSA`,hash:{name:`SHA-256`}},r,new TextEncoder().encode(i));return`${i}.${t.encodeBase64URL(e)}`}return`${i}.signature`}async function E({idToken:t,options:n,verifySignature:i=!1,expectedSub:a,expectedNonce:o}){let s=await _(n),c=i?await w({token:t,options:n,jwksUri:s.jwks_uri}):C(t),l=r.timestamp();if(c?.iss!==s.issuer)throw new e.ProtocolError(`Invalid iss`);if(Array.isArray(c?.aud)?!c.aud.includes(n.clientId):c?.aud!==n.clientId)throw new e.ProtocolError(`Invalid aud`);if(!c?.exp||c.exp<=l)throw new e.ProtocolError(`Token has expired`);if(!c?.sub||a&&c.sub!==a)throw new e.ProtocolError(`Invalid sub`);if(o&&c?.nonce!==o)throw new e.ProtocolError(`Invalid nonce`);return c}async function D({url:e,includeOAuthParams:t=!0,persistState:n=!0,params:r,options:i}){let a=await c();if(a.metadata={},!e){let t=await _(i);e=new URL(t.authorization_endpoint)}if(typeof e==`string`&&(e=new URL(e,globalThis.location.origin)),t){let t=new Set(i.scopes??[`openid`]);e.searchParams.set(`client_id`,i.clientId),e.searchParams.set(`redirect_uri`,i.redirectUri),e.searchParams.set(`response_type`,i.responseType??`code`),e.searchParams.set(`response_mode`,i.responseMode??`query`),e.searchParams.set(`scope`,Array.from(t).join(` `)),e.searchParams.set(`code_challenge_method`,`S256`),e.searchParams.set(`state`,a.id),e.searchParams.set(`code_challenge`,a.codeChallenge),t.has(`openid`)&&e.searchParams.set(`nonce`,a.nonce)}if(r.prompt&&(e.searchParams.set(`prompt`,r.prompt),a.metadata.prompt=r.prompt),r.display&&(e.searchParams.set(`display`,r.display),a.metadata.display=r.display),r.loginHint&&(e.searchParams.set(`login_hint`,r.loginHint),a.metadata.loginHint=r.loginHint),r.acrValues?.length){let t=r.acrValues.filter(Boolean);t.length&&(e.searchParams.set(`acr_values`,t.join(` `)),a.metadata.acrValues=t)}if(r.uiLocales?.length){let t=r.uiLocales.filter(Boolean);t.length&&(e.searchParams.set(`ui_locales`,t.join(` `)),a.metadata.uiLocales=t)}if(r.audiences?.length){let t=r.audiences.filter(Boolean);t.length&&(e.searchParams.set(`audience`,t.join(` `)),a.metadata.audiences=t)}return n&&await i.stateStorage.set(`sty.${a.id}`,u(a)),e}function O({url:e,idToken:t,postLogoutRedirectUri:n}){let r=new URL(e);return r.searchParams.set(`id_token_hint`,t),n&&r.searchParams.set(`post_logout_redirect_uri`,n),r}async function k({url:t,params:n,options:r}){let a=i.createSession(n);if(a.error)throw new e.OidcError(a.error,a.error_description,a.error_uri);if(!a.code)throw new e.ProtocolError(`Invalid or missing authorization code`);let o=`sty.${a.state}`,s=await r.stateStorage.get(o);if(!s)throw new e.ProtocolError(`Invalid or missing state`);let c;try{c=l(s)}catch{throw new e.ProtocolError(`Invalid or missing state`)}await r.stateStorage.delete(o);let u=await _(r),d=t??u.token_endpoint,f=await r.httpClient.sendTokenRequest(d,{grant_type:`authorization_code`,client_id:r.clientId,redirect_uri:r.redirectUri,code_verifier:c.codeVerifier,code:a.code});f.ok||await e.throwTokenEndpointError(f);let p;try{p=await f.json()}catch{throw new e.ProtocolError(`Non-JSON response from token endpoint`)}let m={...n,...i.createSession(p)};if(m.error)throw new e.OidcError(m.error,m.error_description,m.error_uri);return m.id_token&&(m.claims=await E({idToken:m.id_token,expectedNonce:c.nonce,options:r})),m}async function A({url:t,refreshToken:n,options:r,grantType:a=`refresh_token`,clientId:o,audience:s,scope:c,expectedSub:l}){let u={grant_type:a,client_id:o??r.clientId,refresh_token:n};s&&(u.audience=s),c&&(u.scope=c);let d=await _(r),f=t??d.token_endpoint,p=await r.httpClient.sendTokenRequest(f,u);p.ok||await e.throwTokenEndpointError(p);let m;try{m=await p.json()}catch{throw new e.ProtocolError(`Non-JSON response from token endpoint`)}let h=i.createSession(m);if(h.error)throw new e.OidcError(h.error,h.error_description,h.error_uri);return h.id_token&&(h.claims=await E({idToken:h.id_token,expectedSub:l,options:r})),h}async function j({url:t,tokenTypeHint:n,token:r,options:i,clientId:a}){let o=await _(i),s=t??o.revocation_endpoint;if(!s){i.logging?.debug(`Revocation skipped: no revocation_endpoint available`);return}let c=await i.httpClient.sendTokenRequest(s,{client_id:a??i.clientId,token_type_hint:n,token:r});c&&!c.ok&&await e.throwTokenEndpointError(c)}async function M({url:t,params:n,options:r,clientId:i,redirectUri:a,sdkMode:o=`web`}){n.set(`sdk`,o),n.set(`client_id`,i??r.clientId),n.set(`redirect_uri`,a??r.redirectUri);let s=new URL(t);s.search=n.toString();let c=await r.httpClient.request(s);if(!c.ok){if(c.status===400){let t=await c.json();if(t&&typeof t==`object`){if(t.error)throw new e.OidcError(t.error,t.error_description,t.error_uri);if(t.errorKey)throw new e.ProtocolError(t.errorKey)}throw new e.ProtocolError(`Entry request failed`)}e.throwHttpError(c.status,`Entry request failed`)}let l,u;try{l=new URL(await c.text()),u=Object.fromEntries(l.searchParams.entries())}catch{l=new URL(c.url),u=Object.fromEntries(l.searchParams.entries())}let d=u.short_app_id,f=u.session_id,p=u.language||globalThis.navigator?.language||`en-US`;if(!f)throw new e.ProtocolError(`"session_id" is missing from the response`);return{session_id:f,short_app_id:d,language:p}}async function N({url:t,sessionId:n,language:r,options:i}){let a=await i.httpClient.request(t,{method:`GET`,credentials:`include`,headers:{Authorization:`Bearer ${n}`,"Accept-language":r}});a.ok||e.throwHttpError(a.status,`Failed to finalize login session`);let o;try{o=new URL(await a.text())}catch{throw new e.ProtocolError(`Invalid redirect URI`)}if(!o.toString().startsWith(i.redirectUri))throw new e.ProtocolError(`Invalid redirect URI`);return o}async function P({formId:t,body:n,sessionId:r,language:i,options:a}){let o=await a.httpClient.request(new URL(`/flow/api/v1/${t?`form/${t}`:`init`}`,a.issuer),{method:`POST`,credentials:`include`,body:JSON.stringify(n),headers:{Authorization:`Bearer ${r}`,"Content-Type":`application/json`,"Accept-language":i}}),s={};try{s=await o.json()}catch{}if(!o.ok){if(o.status===403)throw new e.SessionExpiredError;if(o.status>=400&&o.status<500&&s?.hostedUrl&&!s.messages)throw new e.FallbackError(new URL(s.hostedUrl),`Received HTTP ${o.status} without messages`);e.throwHttpError(o.status,`Failed to submit login form`)}if(s.hostedUrl&&!s.finalizeUrl&&!s.forms&&!s.messages)throw new e.FallbackError(new URL(s.hostedUrl),`No forms or messages in response`);return s}Object.defineProperty(exports,"S",{enumerable:!0,get:function(){return u}}),Object.defineProperty(exports,"_",{enumerable:!0,get:function(){return P}}),Object.defineProperty(exports,"a",{enumerable:!0,get:function(){return k}}),Object.defineProperty(exports,"b",{enumerable:!0,get:function(){return c}}),Object.defineProperty(exports,"c",{enumerable:!0,get:function(){return x}}),Object.defineProperty(exports,"d",{enumerable:!0,get:function(){return S}}),Object.defineProperty(exports,"f",{enumerable:!0,get:function(){return h}}),Object.defineProperty(exports,"g",{enumerable:!0,get:function(){return j}}),Object.defineProperty(exports,"h",{enumerable:!0,get:function(){return A}}),Object.defineProperty(exports,"i",{enumerable:!0,get:function(){return g}}),Object.defineProperty(exports,"l",{enumerable:!0,get:function(){return b}}),Object.defineProperty(exports,"m",{enumerable:!0,get:function(){return y}}),Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return O}}),Object.defineProperty(exports,"o",{enumerable:!0,get:function(){return M}}),Object.defineProperty(exports,"p",{enumerable:!0,get:function(){return _}}),Object.defineProperty(exports,"r",{enumerable:!0,get:function(){return C}}),Object.defineProperty(exports,"s",{enumerable:!0,get:function(){return N}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return D}}),Object.defineProperty(exports,"u",{enumerable:!0,get:function(){return T}}),Object.defineProperty(exports,"v",{enumerable:!0,get:function(){return E}}),Object.defineProperty(exports,"x",{enumerable:!0,get:function(){return l}}),Object.defineProperty(exports,"y",{enumerable:!0,get:function(){return w}});
|
|
2
|
+
//# sourceMappingURL=oidc.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oidc.cjs","names":[],"sources":["../../src/utils/state.ts","../../src/utils/oidc.ts"],"sourcesContent":["import type { StateData } from '../types/oidc';\nimport { timestamp } from './common';\nimport { generateCodeVerifier, generateCodeChallenge, generateRandomHex } from './oidc';\n\n/**\n * Creates a new state object for OAuth 2.0 authorization requests, including a code verifier and challenge for PKCE.\n *\n * @param {Record<string, unknown>} [metadata={}] Optional metadata to associate with the state.\n * @returns {Promise<StateData>} A promise that resolves to the newly created state object.\n */\nexport async function createState(metadata: Record<string, unknown> = {}): Promise<StateData> {\n\tconst codeVerifier = generateCodeVerifier();\n\n\treturn {\n\t\tid: generateRandomHex(16),\n\t\tcreatedAt: timestamp(),\n\t\tcodeVerifier,\n\t\tmetadata,\n\t\tcodeChallenge: await generateCodeChallenge(codeVerifier),\n\t\tnonce: generateRandomHex(16),\n\t};\n}\n\n/**\n * Parses a serialized state string into a StateData object.\n *\n * @param {string} serialized - The serialized state string to parse.\n * @returns {StateData} The parsed StateData object.\n * @throws {Error} If the serialized string is invalid or cannot be parsed.\n */\nexport function parseState(serialized: string): StateData {\n\treturn JSON.parse(serialized) as StateData;\n}\n\n/**\n * Serializes a StateData object into a string for storage or transmission.\n *\n * @param {StateData} state - The StateData object to serialize.\n * @returns {string} The serialized state string.\n */\nexport function serializeState(state: StateData): string {\n\treturn JSON.stringify(state);\n}\n","import type { ExtraRequestArgs, IdTokenClaims, DiscoveryDocument, SDKOptions, SessionData, EntryResponse, FlowState, SigningKey } from '../types/oidc';\nimport type { NativeFlowState } from '../types/native';\nimport { decodeBase64URL, encodeBase64URL } from './base64url';\nimport { FallbackError, SessionExpiredError, OidcError, ProtocolError, ServerError, NetworkError, throwHttpError, throwTokenEndpointError } from './errors';\nimport { createHttpClient } from './httpClient';\nimport { createSession } from './session';\nimport { createState, parseState, serializeState } from './state';\nimport { redirectUrlHandler, redirectCallbackHandler } from '../handlers/redirect';\nimport { createLocalStorage } from '../storages/local';\nimport { createSessionStorage } from '../storages/session';\nimport { timestamp } from './common';\n\n/**\n * Stores the expiration timestamp of the cached OpenID configuration discovery document.\n */\nlet discoveryDocumentCacheExpiresAt = 0;\n\n/**\n * A promise that represents the ongoing fetch of the OpenID configuration discovery document.\n */\nlet discoveryDocumentFetchPromise: Promise<DiscoveryDocument> | null = null;\n\n/**\n * OpenID configuration discovery document cache.\n */\nlet discoveryDocument: DiscoveryDocument | null = null;\n\n/**\n * JSON Web Key Set (JWKS) cache.\n */\nconst jwksCache = new Map<string, { keys: Array<SigningKey>; expiresAt: number }>();\n\n/**\n * Returns the default flow state for the SDK.\n *\n * @returns {FlowState} The default flow state object.\n */\nexport function getDefaultFlowState(): FlowState {\n\treturn {\n\t\tinitialized: false,\n\t\tsession: null,\n\t\tsessionId: null,\n\t\tshortAppId: null,\n\t\tlanguage: globalThis.navigator?.language ?? 'en-US',\n\t};\n}\n\n/**\n * Returns the default SDK options for the SDK.\n */\nexport const defaultOptions: Partial<SDKOptions> = {\n\tlazyLoad: false,\n\tautoRefresh: true,\n\tserverSessionUri: null,\n\tscopes: ['openid'],\n\tresponseType: 'code',\n\tresponseMode: 'query',\n\tstorageTokenName: 'sty.session',\n\tdiscoveryDocumentCacheTTL: 3600,\n\tjwksCacheTTL: 600,\n} as const;\n\n/**\n * Fetches the OpenID configuration discovery document from the authorization server.\n * Caches the document for a specified duration to avoid unnecessary network requests.\n *\n * @param {SDKOptions} options - The SDK options containing the issuer URL and other configurations.\n * @returns {Promise<DiscoveryDocument>} A promise that resolves to the fetched discovery document.\n * @throws {ServerError} If the discovery document fetch fails with a server error (HTTP 429 or 5xx).\n * @throws {ProtocolError} If the discovery document is missing required fields or has an issuer mismatch.\n */\nexport async function getDiscoveryDocument(options: SDKOptions): Promise<DiscoveryDocument> {\n\tif (discoveryDocument && discoveryDocumentCacheExpiresAt > timestamp()) {\n\t\treturn discoveryDocument;\n\t}\n\n\tif (discoveryDocumentFetchPromise) {\n\t\treturn discoveryDocumentFetchPromise;\n\t}\n\n\tdiscoveryDocumentFetchPromise = (async () => {\n\t\ttry {\n\t\t\tconst response = await options.httpClient.request<DiscoveryDocument>(new URL('/.well-known/openid-configuration', options.issuer));\n\n\t\t\tif (!response.ok) {\n\t\t\t\tthrow new ServerError(`Failed to fetch OIDC metadata`, response.status);\n\t\t\t}\n\n\t\t\tlet metadata: DiscoveryDocument;\n\n\t\t\ttry {\n\t\t\t\tmetadata = await response.json();\n\t\t\t} catch {\n\t\t\t\tthrow new ProtocolError('Non-JSON response from discovery document endpoint');\n\t\t\t}\n\n\t\t\tif (metadata.issuer?.replace(/\\/$/, '') !== options.issuer.replace(/\\/$/, '')) {\n\t\t\t\tthrow new ProtocolError(`Discovery document issuer mismatch: expected ${options.issuer}, got ${metadata.issuer}`);\n\t\t\t}\n\n\t\t\tconst issuerHost = new URL(options.issuer).host;\n\n\t\t\tfor (const field of ['authorization_endpoint', 'token_endpoint', 'jwks_uri'] as const) {\n\t\t\t\tconst endpoint = metadata[field];\n\n\t\t\t\tif (!endpoint) {\n\t\t\t\t\tthrow new ProtocolError(`Discovery document is missing required field: ${field}`);\n\t\t\t\t}\n\n\t\t\t\tconst endpointUrl = new URL(endpoint);\n\n\t\t\t\tif (endpointUrl.protocol !== 'https:' || endpointUrl.host !== issuerHost) {\n\t\t\t\t\tthrow new ProtocolError(`Discovery document field \"${field}\" must be an https:// URL on ${issuerHost}, got ${endpoint}`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (const field of ['end_session_endpoint', 'revocation_endpoint'] as const) {\n\t\t\t\tconst endpoint = metadata[field];\n\n\t\t\t\tif (!endpoint) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst endpointUrl = new URL(endpoint);\n\n\t\t\t\tif (endpointUrl.protocol !== 'https:' || endpointUrl.host !== issuerHost) {\n\t\t\t\t\tthrow new ProtocolError(`Discovery document field \"${field}\" must be an https:// URL on ${issuerHost}, got ${endpoint}`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!metadata.code_challenge_methods_supported?.includes('S256')) {\n\t\t\t\tthrow new ProtocolError('Discovery document does not advertise S256 PKCE support');\n\t\t\t}\n\n\t\t\tdiscoveryDocument = metadata;\n\t\t\tdiscoveryDocumentCacheExpiresAt = timestamp() + options.discoveryDocumentCacheTTL;\n\n\t\t\treturn metadata;\n\t\t} finally {\n\t\t\tdiscoveryDocumentFetchPromise = null;\n\t\t}\n\t})();\n\n\treturn discoveryDocumentFetchPromise;\n}\n\n/**\n * Returns the JWKS for the given URI, from cache unless it's stale or `forceRefresh` is set.\n *\n * @param {Object} options - The options for fetching the JWKS.\n * @param {string} options.jwksUri - The URL of the JWKS endpoint.\n * @param {SDKOptions} options.options - The SDK options containing client ID, storage, and other options.\n * @param {boolean} [options.forceRefresh=false] - Bypasses the cache and fetches a fresh key set.\n * @returns {Promise<{ keys: Array<SigningKey> }>} The (possibly cached) key set.\n * @throws {NetworkError} If the JWKS fetch fails due to network issues.\n * @throws {ServerError} If the JWKS fetch fails with a server error (HTTP 429 or 5xx).\n */\nasync function getJwks({\n\tjwksUri,\n\toptions,\n\tforceRefresh = false,\n}: {\n\tjwksUri: string;\n\toptions: SDKOptions;\n\tforceRefresh?: boolean;\n}): Promise<{ keys: Array<SigningKey> }> {\n\tconst cached = jwksCache.get(jwksUri);\n\n\tif (!forceRefresh && cached && cached.expiresAt > timestamp()) {\n\t\treturn { keys: cached.keys };\n\t}\n\n\tlet jwksResponse: Response;\n\n\ttry {\n\t\tjwksResponse = await fetch(jwksUri);\n\t} catch {\n\t\tthrow new NetworkError(`Failed to fetch JWKS: ${jwksUri}`);\n\t}\n\n\tif (!jwksResponse.ok) {\n\t\tthrow new ServerError(`Failed to fetch JWKS: HTTP ${jwksResponse.status}`, jwksResponse.status);\n\t}\n\n\tconst jwks = (await jwksResponse.json()) as { keys: Array<SigningKey> };\n\n\tjwksCache.set(jwksUri, { keys: jwks.keys, expiresAt: timestamp() + options.jwksCacheTTL });\n\n\treturn jwks;\n}\n\n/**\n * Returns with the SDK options merged with the provided options.\n *\n * @param {SDKInitConfig} options - The SDK initialization configuration.\n * @template InitOptions - The type of the SDK initialization configuration.\n * @template Options - The type of the SDK options.\n * @returns {Options} The merged SDK options.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function getSDKOptions<Options extends SDKOptions = SDKOptions>(options: any): Options {\n\toptions.issuer = options.issuer.endsWith('/') ? options.issuer.slice(0, -1) : options.issuer;\n\toptions.storage ??= createLocalStorage();\n\toptions.stateStorage ??= createSessionStorage();\n\toptions.httpClient ??= createHttpClient(options.logging);\n\toptions.urlHandler ??= redirectUrlHandler;\n\toptions.callbackHandler ??= redirectCallbackHandler;\n\toptions.lazyLoad ??= defaultOptions.lazyLoad;\n\toptions.autoRefresh ??= defaultOptions.autoRefresh;\n\toptions.serverSessionUri ??= defaultOptions.serverSessionUri;\n\n\toptions.scopes ??= defaultOptions.scopes;\n\toptions.responseType ??= defaultOptions.responseType;\n\toptions.responseMode ??= defaultOptions.responseMode;\n\toptions.storageTokenName ??= defaultOptions.storageTokenName;\n\toptions.discoveryDocumentCacheTTL ??= defaultOptions.discoveryDocumentCacheTTL;\n\toptions.jwksCacheTTL ??= defaultOptions.jwksCacheTTL;\n\n\treturn options;\n}\n\n/**\n * Generates a code verifier for PKCE (Proof Key for Code Exchange).\n *\n * @returns {string} A randomly generated code verifier string.\n */\nexport function generateCodeVerifier(): string {\n\tconst bytes = new Uint8Array(32);\n\n\tglobalThis.crypto.getRandomValues(bytes);\n\n\treturn encodeBase64URL(bytes.buffer);\n}\n\n/**\n * Generates a code challenge from a code verifier using SHA-256 hashing.\n *\n * @param {string} codeVerifier The code verifier string.\n * @returns {Promise<string>} A promise that resolves to the generated code challenge.\n */\nexport async function generateCodeChallenge(codeVerifier: string): Promise<string> {\n\tconst encoded = new TextEncoder().encode(codeVerifier);\n\tconst hash = await globalThis.crypto.subtle.digest('SHA-256', encoded);\n\n\treturn encodeBase64URL(hash);\n}\n\n/**\n * Generates a random hexadecimal string of the specified byte length.\n *\n * @param {number} [byteLength=16] - The number of random bytes to generate (default is 16).\n * @returns {string} A randomly generated hexadecimal string.\n */\nexport function generateRandomHex(byteLength = 16): string {\n\tconst bytes = new Uint8Array(byteLength);\n\n\tglobalThis.crypto.getRandomValues(bytes);\n\n\treturn Array.from(bytes)\n\t\t.map((b) => b.toString(16).padStart(2, '0'))\n\t\t.join('');\n}\n\n/**\n * Decodes a JWT token and returns the payload as an object.\n *\n * @template T The expected structure of the JWT payload.\n * @param {string} token - The JWT token to decode.\n * @returns {T} The decoded payload of the JWT token.\n * @throws {ProtocolError} If the token is invalid or has the wrong format.\n */\nexport function decodeJwt<T = Record<string, unknown>>(token: string): T {\n\tconst [, payload] = token.split('.');\n\n\tif (!payload) {\n\t\tthrow new ProtocolError('Invalid JWT: missing payload segment');\n\t}\n\n\ttry {\n\t\treturn JSON.parse(new TextDecoder().decode(decodeBase64URL(payload))) as T;\n\t} catch {\n\t\tthrow new ProtocolError('Invalid JWT: payload is not valid base64url-encoded JSON');\n\t}\n}\n\n/**\n * Verifies a JWT token's signature against a JWKS endpoint.\n * Only RS256 is supported.\n *\n * @param {Object} options - The options for verifying the JWT.\n * @param {string} options.token - The JWT token to verify.\n * @param {string} options.jwksUri - The URL of the JWKS endpoint.\n * @param {SDKOptions} options.options - The SDK options containing client ID, storage, and other options.\n * @template T - The expected structure of the JWT payload.\n * @returns {Promise<T>} The verified payload.\n * @throws {ProtocolError} If the token is invalid, the key is not found, or verification fails.\n */\nexport async function verifyJwt<T = Record<string, unknown>>({ token, jwksUri, options }: { token: string; jwksUri: string; options: SDKOptions }): Promise<T> {\n\tconst parts = token.split('.');\n\n\tif (parts.length !== 3) {\n\t\tthrow new ProtocolError('Invalid JWT: must have 3 parts');\n\t}\n\n\tconst [encodedHeader, encodedPayload, encodedSignature] = parts;\n\tconst header = JSON.parse(new TextDecoder().decode(decodeBase64URL(encodedHeader))) as { kid?: string; alg?: string };\n\n\tif (header.alg !== 'RS256') {\n\t\tthrow new ProtocolError(`Unsupported JWT algorithm: ${header.alg}`);\n\t}\n\n\tlet jwks = await getJwks({ jwksUri, options });\n\tlet signingKey = header.kid ? jwks.keys.find((k) => k.kid === header.kid) : jwks.keys.find((k) => k.alg === 'RS256');\n\n\tif (!signingKey && header.kid) {\n\t\tjwks = await getJwks({ jwksUri, options, forceRefresh: true });\n\t\tsigningKey = jwks.keys.find((k) => k.kid === header.kid);\n\t}\n\n\tif (!signingKey) {\n\t\tthrow new ProtocolError(`No matching key found in JWKS${header.kid ? ` for kid: ${header.kid}` : ''}`);\n\t}\n\n\tconst cryptoKey = await globalThis.crypto.subtle.importKey(\n\t\t'jwk',\n\t\t{ kty: signingKey.kty, n: signingKey.n, e: signingKey.e, alg: signingKey.alg, use: signingKey.use },\n\t\t{ name: 'RSASSA-PKCS1-v1_5', hash: { name: 'SHA-256' } },\n\t\tfalse,\n\t\t['verify'],\n\t);\n\tconst signature = decodeBase64URL(encodedSignature);\n\tconst data = new TextEncoder().encode(`${encodedHeader}.${encodedPayload}`);\n\tconst valid = await globalThis.crypto.subtle.verify({ name: 'RSASSA-PKCS1-v1_5' }, cryptoKey, signature, data);\n\n\tif (!valid) {\n\t\tthrow new ProtocolError('JWT signature verification failed');\n\t}\n\n\treturn JSON.parse(new TextDecoder().decode(decodeBase64URL(encodedPayload))) as T;\n}\n\n/**\n * Generates a signed JWT token using the provided header, payload, and private key.\n *\n * @param {object} header - The JWT header.\n * @param {object} payload - The JWT payload.\n * @param {CryptoKey} [privateKey] - The private key to sign the JWT. If not provided, an unsigned token will be generated.\n * @returns {Promise<string>} A promise that resolves to the signed JWT token.\n */\nexport async function generateJwt(header: object, payload: object, privateKey?: CryptoKey): Promise<string> {\n\tconst encodedHeader = encodeBase64URL(new TextEncoder().encode(JSON.stringify(header)).buffer);\n\tconst encodedPayload = encodeBase64URL(new TextEncoder().encode(JSON.stringify(payload)).buffer);\n\tconst encodedToken = `${encodedHeader}.${encodedPayload}`;\n\n\tif (privateKey) {\n\t\tconst signature = await globalThis.crypto.subtle.sign(\n\t\t\t{\n\t\t\t\tname: 'ECDSA',\n\t\t\t\thash: { name: 'SHA-256' },\n\t\t\t},\n\t\t\tprivateKey,\n\t\t\tnew TextEncoder().encode(encodedToken),\n\t\t);\n\n\t\treturn `${encodedToken}.${encodeBase64URL(signature)}`;\n\t}\n\n\treturn `${encodedToken}.signature`;\n}\n\n/**\n * Verifies and validates an ID token's claims.\n *\n * @param {Object} options - The options for verifying the ID token\n * @param {string} options.idToken - The ID token to verify\n * @param {SDKOptions} options.options - The SDK options containing client ID, storage, and other options\n * @param {string} [options.expectedSub] - Optional expected subject (`sub`) claim to validate against the ID token\n * @param {string} [options.expectedNonce] - Optional expected nonce claim to validate against the ID token\n * @returns {Promise<IdTokenClaims>} The verified, validated claims.\n * @throws {ProtocolError} If the signature, `iss`, `aud`, `exp`, or `sub` fail validation.\n */\nexport async function verifyIdToken({\n\tidToken,\n\toptions,\n\tverifySignature = false,\n\texpectedSub,\n\texpectedNonce,\n}: {\n\tidToken: string;\n\toptions: SDKOptions;\n\tverifySignature?: boolean;\n\texpectedSub?: string;\n\texpectedNonce?: string;\n}): Promise<IdTokenClaims> {\n\tconst metadata = await getDiscoveryDocument(options);\n\tconst claims = verifySignature ? await verifyJwt<IdTokenClaims>({ token: idToken, options, jwksUri: metadata.jwks_uri }) : decodeJwt<IdTokenClaims>(idToken);\n\tconst now = timestamp();\n\n\tif (claims?.iss !== metadata.issuer) {\n\t\tthrow new ProtocolError('Invalid iss');\n\t}\n\tif (Array.isArray(claims?.aud) ? !claims.aud.includes(options.clientId) : claims?.aud !== options.clientId) {\n\t\tthrow new ProtocolError('Invalid aud');\n\t}\n\tif (!claims?.exp || claims.exp <= now) {\n\t\tthrow new ProtocolError('Token has expired');\n\t}\n\tif (!claims?.sub || (expectedSub && claims.sub !== expectedSub)) {\n\t\tthrow new ProtocolError('Invalid sub');\n\t}\n\tif (expectedNonce && claims?.nonce !== expectedNonce) {\n\t\tthrow new ProtocolError('Invalid nonce');\n\t}\n\n\treturn claims;\n}\n\n/**\n * Builds the authorization URL with the provided parameters and configuration.\n *\n * @param {Object} options - The options for building the login URL and starting the session\n * @param {ExtraRequestArgs} options.params - The parameters for the authorization request, including optional prompts and hints\n * @param {SDKOptions} options.options - The SDK options containing client ID, redirect URI, storage, and other options\n * @returns {Promise<URL>} A promise that resolves to the constructed authorization URL\n * @throws {Error} If fetching OIDC metadata fails or writing the PKCE state to storage fails.\n */\nexport async function buildAuthorizationUrl<URLHandlerParams extends ExtraRequestArgs = ExtraRequestArgs>({\n\turl,\n\tincludeOAuthParams = true,\n\tpersistState = true,\n\tparams,\n\toptions,\n}: {\n\turl?: string | null | URL;\n\tincludeOAuthParams?: boolean;\n\tpersistState?: boolean;\n\tparams: URLHandlerParams;\n\toptions: SDKOptions;\n}): Promise<URL> {\n\tconst stateData = await createState();\n\tstateData.metadata = {};\n\n\tif (!url) {\n\t\tconst metadata = await getDiscoveryDocument(options);\n\t\turl = new URL(metadata.authorization_endpoint);\n\t}\n\tif (typeof url === 'string') {\n\t\turl = new URL(url, globalThis.location.origin);\n\t}\n\n\tif (includeOAuthParams) {\n\t\tconst scopes = new Set(options.scopes ?? ['openid']);\n\n\t\turl.searchParams.set('client_id', options.clientId);\n\t\turl.searchParams.set('redirect_uri', options.redirectUri);\n\t\turl.searchParams.set('response_type', options.responseType ?? 'code');\n\t\turl.searchParams.set('response_mode', options.responseMode ?? 'query');\n\t\turl.searchParams.set('scope', Array.from(scopes).join(' '));\n\t\turl.searchParams.set('code_challenge_method', 'S256');\n\t\turl.searchParams.set('state', stateData.id);\n\t\turl.searchParams.set('code_challenge', stateData.codeChallenge);\n\n\t\tif (scopes.has('openid')) {\n\t\t\turl.searchParams.set('nonce', stateData.nonce);\n\t\t}\n\t}\n\n\tif (params.prompt) {\n\t\turl.searchParams.set('prompt', params.prompt);\n\t\tstateData.metadata.prompt = params.prompt;\n\t}\n\tif (params.display) {\n\t\turl.searchParams.set('display', params.display);\n\t\tstateData.metadata.display = params.display;\n\t}\n\tif (params.loginHint) {\n\t\turl.searchParams.set('login_hint', params.loginHint);\n\t\tstateData.metadata.loginHint = params.loginHint;\n\t}\n\tif (params.acrValues?.length) {\n\t\tconst acrValues = params.acrValues.filter(Boolean);\n\n\t\tif (acrValues.length) {\n\t\t\turl.searchParams.set('acr_values', acrValues.join(' '));\n\t\t\tstateData.metadata.acrValues = acrValues;\n\t\t}\n\t}\n\tif (params.uiLocales?.length) {\n\t\tconst uiLocales = params.uiLocales.filter(Boolean);\n\n\t\tif (uiLocales.length) {\n\t\t\turl.searchParams.set('ui_locales', uiLocales.join(' '));\n\t\t\tstateData.metadata.uiLocales = uiLocales;\n\t\t}\n\t}\n\tif (params.audiences?.length) {\n\t\tconst audiences = params.audiences.filter(Boolean);\n\n\t\tif (audiences.length) {\n\t\t\turl.searchParams.set('audience', audiences.join(' '));\n\t\t\tstateData.metadata.audiences = audiences;\n\t\t}\n\t}\n\n\tif (persistState) {\n\t\tawait options.stateStorage.set(`sty.${stateData.id}`, serializeState(stateData));\n\t}\n\n\treturn url;\n}\n\n/**\n * Builds the end session (logout) URL with optional parameters for ID token hint and post-logout redirect URI.\n *\n * @param {Object} options - The options for building the end session URL\n * @param {string | URL} options.url - The base URL for the end session endpoint\n * @param {string} options.idToken - The ID token to include as a hint for the end session request\n * @param {string} [options.postLogoutRedirectUri] - Optional URI to redirect to after logout\n * @returns {URL} A promise that resolves to the constructed end session URL\n * @throws {Error} If fetching metadata fails or the end session endpoint is not available\n */\nexport function buildEndSessionUrl({ url, idToken, postLogoutRedirectUri }: { url: string | URL; idToken: string; postLogoutRedirectUri?: string }): URL {\n\tconst endSessionUrl = new URL(url);\n\n\tendSessionUrl.searchParams.set('id_token_hint', idToken);\n\n\tif (postLogoutRedirectUri) {\n\t\tendSessionUrl.searchParams.set('post_logout_redirect_uri', postLogoutRedirectUri);\n\t}\n\n\treturn endSessionUrl;\n}\n\n/**\n * Exchanges an authorization code for tokens by sending a request to the token endpoint.\n * Validates the PKCE state and ID token claims, and returns the session data.\n *\n * @param {Object} options - The options for exchanging the authorization code\n * @param {string | URL} [options.url] - The token endpoint URL (optional, will be fetched from metadata if not provided)\n * @param {Record<string, string>} options.params - The parameters received from the authorization server, including the authorization code and state\n * @param {SDKOptions} options.options - The SDK options containing client ID, redirect URI, storage, and other options\n * @returns {Promise<SessionData>} A promise that resolves to the session data containing tokens and claims\n * @throws {OidcError} If the token endpoint returns an OIDC error response\n * @throws {ServerError} If the token endpoint request fails with a server error (HTTP 429 or 5xx)\n * @throws {NetworkError} If the token endpoint request fails due to network issues\n * @throws {ProtocolError} If the authorization code or state is invalid, or if the token endpoint returns an error\n * @throws {ProtocolError} If the authorization code or state is invalid, or if the token endpoint returns an error\n */\nexport async function exchangeCode({\n\turl,\n\tparams,\n\toptions,\n}: {\n\turl?: string | URL;\n\tparams: Record<string, string>;\n\toptions: SDKOptions;\n}): Promise<SessionData> {\n\tconst session = createSession(params);\n\n\tif (session.error) {\n\t\tthrow new OidcError(session.error, session.error_description, session.error_uri);\n\t}\n\tif (!session.code) {\n\t\tthrow new ProtocolError('Invalid or missing authorization code');\n\t}\n\n\tconst stateKey = `sty.${session.state}`;\n\tconst serializedState = await options.stateStorage.get(stateKey);\n\n\tif (!serializedState) {\n\t\tthrow new ProtocolError('Invalid or missing state');\n\t}\n\n\tlet state;\n\n\ttry {\n\t\tstate = parseState(serializedState);\n\t} catch {\n\t\tthrow new ProtocolError('Invalid or missing state');\n\t}\n\n\tawait options.stateStorage.delete(stateKey);\n\n\tconst metadata = await getDiscoveryDocument(options);\n\tconst tokenUrl = url ?? metadata.token_endpoint;\n\tconst response = await options.httpClient.sendTokenRequest<Record<string, string>>(tokenUrl, {\n\t\tgrant_type: 'authorization_code',\n\t\tclient_id: options.clientId,\n\t\tredirect_uri: options.redirectUri,\n\t\tcode_verifier: state.codeVerifier,\n\t\tcode: session.code,\n\t});\n\n\tif (!response.ok) {\n\t\tawait throwTokenEndpointError(response);\n\t}\n\n\tlet data: Record<string, string>;\n\n\ttry {\n\t\tdata = await response.json();\n\t} catch {\n\t\tthrow new ProtocolError('Non-JSON response from token endpoint');\n\t}\n\n\tconst updatedSession: SessionData = { ...params, ...createSession(data) };\n\n\tif (updatedSession.error) {\n\t\tthrow new OidcError(updatedSession.error, updatedSession.error_description, updatedSession.error_uri);\n\t}\n\n\tif (updatedSession.id_token) {\n\t\tupdatedSession.claims = await verifyIdToken({ idToken: updatedSession.id_token, expectedNonce: state.nonce, options });\n\t}\n\n\treturn updatedSession;\n}\n\n/**\n * Refreshes the access token using the stored refresh token and persists the updated session.\n *\n * @param {Object} options - The options for refreshing the access token\n * @param {string} options.url - The token endpoint URL\n * @param {string} options.refreshToken - The refresh token to use for refreshing the access token\n * @param {SDKOptions} options.options - The SDK options containing client ID, storage, and other options\n * @param {string} [options.grantType='refresh_token'] - The grant type to use for the token refresh request (default is 'refresh_token')\n * @param {string} [options.clientId] - Optional client ID to override the default client ID in the SDK options\n * @param {string} [options.audience] - Optional audience to include in the token refresh request\n * @param {string} [options.scope] - Optional scope to include in the token refresh request\n * @returns {Promise<SessionData>} A promise that resolves to the updated session data with refreshed tokens\n * @throws {ServerError} If the token refresh request fails with a server error (HTTP 429 or 5xx)\n * @throws {NetworkError} If the token refresh request fails due to network issues\n * @throws {OidcError} If the token refresh request returns an OIDC error response\n * @throws {ProtocolError} If the token refresh request returns an error or the ID token claims are invalid\n */\nexport async function refreshToken({\n\turl,\n\trefreshToken,\n\toptions,\n\tgrantType = 'refresh_token',\n\tclientId,\n\taudience,\n\tscope,\n\texpectedSub,\n}: {\n\turl?: string | URL;\n\trefreshToken: string;\n\toptions: SDKOptions;\n\tgrantType?: string;\n\tclientId?: string;\n\taudience?: string;\n\tscope?: string;\n\texpectedSub?: string;\n}): Promise<SessionData> {\n\tconst params: Record<string, string> = {\n\t\tgrant_type: grantType,\n\t\tclient_id: clientId ?? options.clientId,\n\t\trefresh_token: refreshToken,\n\t};\n\n\tif (audience) {\n\t\tparams.audience = audience;\n\t}\n\n\tif (scope) {\n\t\tparams.scope = scope;\n\t}\n\n\tconst metadata = await getDiscoveryDocument(options);\n\tconst refreshUrl = url ?? metadata.token_endpoint;\n\tconst response = await options.httpClient.sendTokenRequest<Record<string, string>>(refreshUrl, params);\n\n\tif (!response.ok) {\n\t\tawait throwTokenEndpointError(response);\n\t}\n\n\tlet data: Record<string, string>;\n\n\ttry {\n\t\tdata = await response.json();\n\t} catch {\n\t\tthrow new ProtocolError('Non-JSON response from token endpoint');\n\t}\n\n\tconst updatedSession: SessionData = createSession(data);\n\n\tif (updatedSession.error) {\n\t\tthrow new OidcError(updatedSession.error, updatedSession.error_description, updatedSession.error_uri);\n\t}\n\n\tif (updatedSession.id_token) {\n\t\tupdatedSession.claims = await verifyIdToken({ idToken: updatedSession.id_token, expectedSub, options });\n\t}\n\n\treturn updatedSession;\n}\n\n/**\n * Revokes the best available token (refresh token preferred, then access token) and removes the session from storage.\n *\n * @param {Object} options - The options for revoking the token\n * @param {string | URL} options.url - The revocation endpoint URL\n * @param {string} options.tokenTypeHint - The type of token to revoke ('refresh_token' or 'access_token')\n * @param {string} options.token - The token to revoke\n * @param {SDKOptions} options.options - The SDK options containing client ID, storage, and other options\n * @param {string} [options.clientId] - Optional client ID to override the default client ID in the SDK options\n * @returns {Promise<void>} A promise that resolves when the token is revoked and the session is cleared from storage\n * @throws {ServerError} If the token revocation request fails with a server error (HTTP 429 or 5xx)\n * @throws {ProtocolError} If the token revocation request returns an error or the ID token claims are invalid\n */\nexport async function revokeToken({\n\turl,\n\ttokenTypeHint,\n\ttoken,\n\toptions,\n\tclientId,\n}: {\n\turl?: string | URL;\n\ttokenTypeHint: string;\n\ttoken: string;\n\toptions: SDKOptions;\n\tclientId?: string;\n}): Promise<void> {\n\tconst metadata = await getDiscoveryDocument(options);\n\tconst revokeUrl = url ?? metadata.revocation_endpoint;\n\n\tif (!revokeUrl) {\n\t\toptions.logging?.debug('Revocation skipped: no revocation_endpoint available');\n\t\treturn;\n\t}\n\n\tconst response = await options.httpClient.sendTokenRequest<Record<string, string>>(revokeUrl, {\n\t\tclient_id: clientId ?? options.clientId,\n\t\ttoken_type_hint: tokenTypeHint,\n\t\ttoken,\n\t});\n\n\tif (response && !response.ok) {\n\t\tawait throwTokenEndpointError(response);\n\t}\n}\n\n/**\n * Fetches the entry flow from the specified URL with the provided parameters and SDK options.\n *\n * @param {Object} options\n * @param {string | URL} options.url - The URL to request the entry flow from\n * @param {URLSearchParams} options.params - The parameters to include in the entry request\n * @param {SDKOptions} options.options - The SDK options containing client ID, redirect URI, storage, and other options\n * @param {string} [options.clientId] - Optional client ID to override the default client ID in the SDK options\n * @param {string} [options.redirectUri] - Optional redirect URI to override the default redirect URI in the SDK options\n * @param {string} [options.sdkMode='web'] - Optional SDK mode to include in the entry request (default is 'web')\n * @returns {Promise<EntryResponse>} A promise resolving to the entry result.\n * @throws {OidcError} If the entry request returns an OIDC error response.\n * @throws {ServerError} If the entry request fails with a server error (HTTP 429 or 5xx).\n * @throws {ProtocolError} If the entry request fails with a protocol error or missing required fields.\n */\nexport async function fetchFlowEntry({\n\turl,\n\tparams,\n\toptions,\n\tclientId,\n\tredirectUri,\n\tsdkMode = 'web',\n}: {\n\turl: string | URL;\n\tparams: URLSearchParams;\n\toptions: SDKOptions;\n\tclientId?: string;\n\tredirectUri?: string;\n\tsdkMode?: string;\n}): Promise<EntryResponse> {\n\tparams.set('sdk', sdkMode);\n\tparams.set('client_id', clientId ?? options.clientId);\n\tparams.set('redirect_uri', redirectUri ?? options.redirectUri);\n\n\tconst requestUrl = new URL(url);\n\trequestUrl.search = params.toString();\n\n\tconst response = await options.httpClient.request<string | Record<string, string>>(requestUrl);\n\n\tif (!response.ok) {\n\t\tif (response.status === 400) {\n\t\t\tconst data = await response.json();\n\n\t\t\tif (data && typeof data === 'object') {\n\t\t\t\tif (data.error) {\n\t\t\t\t\tthrow new OidcError(data.error, data.error_description, data.error_uri);\n\t\t\t\t} else if (data.errorKey) {\n\t\t\t\t\tthrow new ProtocolError(data.errorKey);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthrow new ProtocolError('Entry request failed');\n\t\t}\n\n\t\tthrowHttpError(response.status, 'Entry request failed');\n\t}\n\n\tlet uri: URL;\n\tlet searchParams: Record<string, string>;\n\n\ttry {\n\t\turi = new URL(await response.text());\n\t\tsearchParams = Object.fromEntries(uri.searchParams.entries());\n\t} catch {\n\t\turi = new URL(response.url);\n\t\tsearchParams = Object.fromEntries(uri.searchParams.entries());\n\t}\n\n\tconst shortAppId = searchParams.short_app_id;\n\tconst sessionId = searchParams.session_id;\n\tconst language = searchParams.language || globalThis.navigator?.language || 'en-US';\n\n\tif (!sessionId) {\n\t\tthrow new ProtocolError('\"session_id\" is missing from the response');\n\t}\n\n\treturn { session_id: sessionId, short_app_id: shortAppId, language };\n}\n\n/**\n * Finalizes the login session using the provided url.\n *\n * @param {Object} options - The options for finalizing the session\n * @param {string | URL} options.url - The URL to finalize the session.\n * @param {string} options.sessionId - The session ID to finalize the session with.\n * @param {string} options.language - The language to use for the session.\n * @param {SDKOptions} options.options - The SDK options containing client ID, redirect URI, storage, and other options.\n * @returns {Promise<URL>} A promise that resolves to the redirect URL after finalizing the session.\n * @throws {ServerError} If the request to finalize the session fails with a server error (HTTP 429 or 5xx).\n * @throws {ProtocolError} If the response from the server is invalid or does not contain a valid redirect URI.\n */\nexport async function finalizeLoginSession({\n\turl,\n\tsessionId,\n\tlanguage,\n\toptions,\n}: {\n\turl: string | URL;\n\tsessionId: string;\n\tlanguage: string;\n\toptions: SDKOptions;\n}): Promise<URL> {\n\tconst response = await options.httpClient.request(url, {\n\t\tmethod: 'GET',\n\t\tcredentials: 'include',\n\t\theaders: {\n\t\t\tAuthorization: `Bearer ${sessionId}`,\n\t\t\t'Accept-language': language,\n\t\t},\n\t});\n\n\tif (!response.ok) {\n\t\tthrowHttpError(response.status, 'Failed to finalize login session');\n\t}\n\n\tlet redirectUri: URL;\n\n\ttry {\n\t\tredirectUri = new URL(await response.text());\n\t} catch {\n\t\tthrow new ProtocolError('Invalid redirect URI');\n\t}\n\n\tif (!redirectUri.toString().startsWith(options.redirectUri)) {\n\t\tthrow new ProtocolError('Invalid redirect URI');\n\t}\n\n\treturn redirectUri;\n}\n\n/**\n * Submits a login form to the authentication server.\n *\n * @param {Object} options - The options for submitting the form.\n * @param {string} [options.formId] - The ID of the form to submit. If not provided, the init endpoint is used.\n * @param {Record<string, unknown>} [options.body] - The form data to include in the request body.\n * @param {string} options.sessionId - The session ID for the current authentication session.\n * @param {string} options.language - The language preference sent in the `Accept-language` header.\n * @param {SDKOptions} options.options - The SDK options.\n * @returns {Promise<NativeFlowState>} A promise that resolves to the current login flow state.\n * @throws {ServerError} If the server returns a non-recoverable HTTP error.\n * @throws {FallbackError} If the server indicates the flow should fall back to the hosted UI.\n * @throws {SessionExpiredError} If the session has expired (HTTP 403).\n */\nexport async function submitLoginForm({\n\tformId,\n\tbody,\n\tsessionId,\n\tlanguage,\n\toptions,\n}: {\n\tformId?: string;\n\tbody?: Record<string, unknown>;\n\tsessionId: string;\n\tlanguage: string;\n\toptions: SDKOptions;\n}): Promise<NativeFlowState> {\n\tconst response = await options.httpClient.request<NativeFlowState>(new URL(`/flow/api/v1/${formId ? `form/${formId}` : 'init'}`, options.issuer), {\n\t\tmethod: 'POST',\n\t\tcredentials: 'include',\n\t\tbody: JSON.stringify(body),\n\t\theaders: {\n\t\t\tAuthorization: `Bearer ${sessionId}`,\n\t\t\t'Content-Type': 'application/json',\n\t\t\t'Accept-language': language,\n\t\t},\n\t});\n\tlet data: NativeFlowState = {};\n\n\ttry {\n\t\tdata = await response.json();\n\t} catch {}\n\n\tif (!response.ok) {\n\t\tif (response.status === 403) {\n\t\t\tthrow new SessionExpiredError();\n\t\t}\n\n\t\tif (response.status >= 400 && response.status < 500 && data?.hostedUrl && !data.messages) {\n\t\t\tthrow new FallbackError(new URL(data.hostedUrl), `Received HTTP ${response.status} without messages`);\n\t\t}\n\n\t\tthrowHttpError(response.status, 'Failed to submit login form');\n\t}\n\n\tif (data.hostedUrl && !data.finalizeUrl && !data.forms && !data.messages) {\n\t\tthrow new FallbackError(new URL(data.hostedUrl), 'No forms or messages in response');\n\t}\n\n\treturn data;\n}\n"],"mappings":"iSAUA,eAAsB,EAAY,EAAoC,CAAC,EAAuB,CAC7F,IAAM,EAAe,EAAqB,EAE1C,MAAO,CACN,GAAI,EAAkB,EAAE,EACxB,UAAW,EAAA,UAAU,EACrB,eACA,WACA,cAAe,MAAM,EAAsB,CAAY,EACvD,MAAO,EAAkB,EAAE,CAC5B,CACD,CASA,SAAgB,EAAW,EAA+B,CACzD,OAAO,KAAK,MAAM,CAAU,CAC7B,CAQA,SAAgB,EAAe,EAA0B,CACxD,OAAO,KAAK,UAAU,CAAK,CAC5B,CC3BA,IAAI,EAAkC,EAKlC,EAAmE,KAKnE,EAA8C,KAK5C,EAAY,IAAI,IAOtB,SAAgB,GAAiC,CAChD,MAAO,CACN,YAAa,GACb,QAAS,KACT,UAAW,KACX,WAAY,KACZ,SAAU,WAAW,WAAW,UAAY,OAC7C,CACD,CAKA,IAAa,EAAsC,CAClD,SAAU,GACV,YAAa,GACb,iBAAkB,KAClB,OAAQ,CAAC,QAAQ,EACjB,aAAc,OACd,aAAc,QACd,iBAAkB,cAClB,0BAA2B,KAC3B,aAAc,GACf,EAWA,eAAsB,EAAqB,EAAiD,CAwE3F,OAvEI,GAAqB,EAAkC,EAAA,UAAU,EAC7D,EAGJ,IAIJ,GAAiC,SAAY,CAC5C,GAAI,CACH,IAAM,EAAW,MAAM,EAAQ,WAAW,QAA2B,IAAI,IAAI,oCAAqC,EAAQ,MAAM,CAAC,EAEjI,GAAI,CAAC,EAAS,GACb,MAAM,IAAI,EAAA,YAAY,gCAAiC,EAAS,MAAM,EAGvE,IAAI,EAEJ,GAAI,CACH,EAAW,MAAM,EAAS,KAAK,CAChC,MAAQ,CACP,MAAM,IAAI,EAAA,cAAc,oDAAoD,CAC7E,CAEA,GAAI,EAAS,QAAQ,QAAQ,MAAO,EAAE,IAAM,EAAQ,OAAO,QAAQ,MAAO,EAAE,EAC3E,MAAM,IAAI,EAAA,cAAc,gDAAgD,EAAQ,OAAO,QAAQ,EAAS,QAAQ,EAGjH,IAAM,EAAa,IAAI,IAAI,EAAQ,MAAM,CAAC,CAAC,KAE3C,IAAK,IAAM,IAAS,CAAC,yBAA0B,iBAAkB,UAAU,EAAY,CACtF,IAAM,EAAW,EAAS,GAE1B,GAAI,CAAC,EACJ,MAAM,IAAI,EAAA,cAAc,iDAAiD,GAAO,EAGjF,IAAM,EAAc,IAAI,IAAI,CAAQ,EAEpC,GAAI,EAAY,WAAa,UAAY,EAAY,OAAS,EAC7D,MAAM,IAAI,EAAA,cAAc,6BAA6B,EAAM,+BAA+B,EAAW,QAAQ,GAAU,CAEzH,CAEA,IAAK,IAAM,IAAS,CAAC,uBAAwB,qBAAqB,EAAY,CAC7E,IAAM,EAAW,EAAS,GAE1B,GAAI,CAAC,EACJ,SAGD,IAAM,EAAc,IAAI,IAAI,CAAQ,EAEpC,GAAI,EAAY,WAAa,UAAY,EAAY,OAAS,EAC7D,MAAM,IAAI,EAAA,cAAc,6BAA6B,EAAM,+BAA+B,EAAW,QAAQ,GAAU,CAEzH,CAEA,GAAI,CAAC,EAAS,kCAAkC,SAAS,MAAM,EAC9D,MAAM,IAAI,EAAA,cAAc,yDAAyD,EAMlF,MAHA,GAAoB,EACpB,EAAkC,EAAA,UAAU,EAAI,EAAQ,0BAEjD,CACR,QAAU,CACT,EAAgC,IACjC,CACD,EAAA,CAAG,EAEI,EACR,CAaA,eAAe,EAAQ,CACtB,UACA,UACA,eAAe,IAKyB,CACxC,IAAM,EAAS,EAAU,IAAI,CAAO,EAEpC,GAAI,CAAC,GAAgB,GAAU,EAAO,UAAY,EAAA,UAAU,EAC3D,MAAO,CAAE,KAAM,EAAO,IAAK,EAG5B,IAAI,EAEJ,GAAI,CACH,EAAe,MAAM,MAAM,CAAO,CACnC,MAAQ,CACP,MAAM,IAAI,EAAA,aAAa,yBAAyB,GAAS,CAC1D,CAEA,GAAI,CAAC,EAAa,GACjB,MAAM,IAAI,EAAA,YAAY,8BAA8B,EAAa,SAAU,EAAa,MAAM,EAG/F,IAAM,EAAQ,MAAM,EAAa,KAAK,EAItC,OAFA,EAAU,IAAI,EAAS,CAAE,KAAM,EAAK,KAAM,UAAW,EAAA,UAAU,EAAI,EAAQ,YAAa,CAAC,EAElF,CACR,CAWA,SAAgB,EAAuD,EAAuB,CAkB7F,MAjBA,GAAQ,OAAS,EAAQ,OAAO,SAAS,GAAG,EAAI,EAAQ,OAAO,MAAM,EAAG,EAAE,EAAI,EAAQ,OACtF,EAAQ,UAAY,EAAA,mBAAmB,EACvC,EAAQ,eAAiB,EAAA,qBAAqB,EAC9C,EAAQ,aAAe,EAAA,iBAAiB,EAAQ,OAAO,EACvD,EAAQ,aAAe,EAAA,mBACvB,EAAQ,kBAAoB,EAAA,wBAC5B,EAAQ,WAAa,EAAe,SACpC,EAAQ,cAAgB,EAAe,YACvC,EAAQ,mBAAqB,EAAe,iBAE5C,EAAQ,SAAW,EAAe,OAClC,EAAQ,eAAiB,EAAe,aACxC,EAAQ,eAAiB,EAAe,aACxC,EAAQ,mBAAqB,EAAe,iBAC5C,EAAQ,4BAA8B,EAAe,0BACrD,EAAQ,eAAiB,EAAe,aAEjC,CACR,CAOA,SAAgB,GAA+B,CAC9C,IAAM,EAAQ,IAAI,WAAW,EAAE,EAI/B,OAFA,WAAW,OAAO,gBAAgB,CAAK,EAEhC,EAAA,gBAAgB,EAAM,MAAM,CACpC,CAQA,eAAsB,EAAsB,EAAuC,CAClF,IAAM,EAAU,IAAI,YAAY,CAAC,CAAC,OAAO,CAAY,EAC/C,EAAO,MAAM,WAAW,OAAO,OAAO,OAAO,UAAW,CAAO,EAErE,OAAO,EAAA,gBAAgB,CAAI,CAC5B,CAQA,SAAgB,EAAkB,EAAa,GAAY,CAC1D,IAAM,EAAQ,IAAI,WAAW,CAAU,EAIvC,OAFA,WAAW,OAAO,gBAAgB,CAAK,EAEhC,MAAM,KAAK,CAAK,CAAC,CACtB,IAAK,GAAM,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,EAAG,GAAG,CAAC,CAAC,CAC3C,KAAK,EAAE,CACV,CAUA,SAAgB,EAAuC,EAAkB,CACxE,GAAM,EAAG,GAAW,EAAM,MAAM,GAAG,EAEnC,GAAI,CAAC,EACJ,MAAM,IAAI,EAAA,cAAc,sCAAsC,EAG/D,GAAI,CACH,OAAO,KAAK,MAAM,IAAI,YAAY,CAAC,CAAC,OAAO,EAAA,gBAAgB,CAAO,CAAC,CAAC,CACrE,MAAQ,CACP,MAAM,IAAI,EAAA,cAAc,0DAA0D,CACnF,CACD,CAcA,eAAsB,EAAuC,CAAE,QAAO,UAAS,WAAgF,CAC9J,IAAM,EAAQ,EAAM,MAAM,GAAG,EAE7B,GAAI,EAAM,SAAW,EACpB,MAAM,IAAI,EAAA,cAAc,gCAAgC,EAGzD,GAAM,CAAC,EAAe,EAAgB,GAAoB,EACpD,EAAS,KAAK,MAAM,IAAI,YAAY,CAAC,CAAC,OAAO,EAAA,gBAAgB,CAAa,CAAC,CAAC,EAElF,GAAI,EAAO,MAAQ,QAClB,MAAM,IAAI,EAAA,cAAc,8BAA8B,EAAO,KAAK,EAGnE,IAAI,EAAO,MAAM,EAAQ,CAAE,UAAS,SAAQ,CAAC,EACzC,EAAa,EAAO,IAAM,EAAK,KAAK,KAAM,GAAM,EAAE,MAAQ,EAAO,GAAG,EAAI,EAAK,KAAK,KAAM,GAAM,EAAE,MAAQ,OAAO,EAOnH,GALI,CAAC,GAAc,EAAO,MACzB,EAAO,MAAM,EAAQ,CAAE,UAAS,UAAS,aAAc,EAAK,CAAC,EAC7D,EAAa,EAAK,KAAK,KAAM,GAAM,EAAE,MAAQ,EAAO,GAAG,GAGpD,CAAC,EACJ,MAAM,IAAI,EAAA,cAAc,gCAAgC,EAAO,IAAM,aAAa,EAAO,MAAQ,IAAI,EAGtG,IAAM,EAAY,MAAM,WAAW,OAAO,OAAO,UAChD,MACA,CAAE,IAAK,EAAW,IAAK,EAAG,EAAW,EAAG,EAAG,EAAW,EAAG,IAAK,EAAW,IAAK,IAAK,EAAW,GAAI,EAClG,CAAE,KAAM,oBAAqB,KAAM,CAAE,KAAM,SAAU,CAAE,EACvD,GACA,CAAC,QAAQ,CACV,EACM,EAAY,EAAA,gBAAgB,CAAgB,EAC5C,EAAO,IAAI,YAAY,CAAC,CAAC,OAAO,GAAG,EAAc,GAAG,GAAgB,EAG1E,GAAI,CAAC,MAFe,WAAW,OAAO,OAAO,OAAO,CAAE,KAAM,mBAAoB,EAAG,EAAW,EAAW,CAAI,EAG5G,MAAM,IAAI,EAAA,cAAc,mCAAmC,EAG5D,OAAO,KAAK,MAAM,IAAI,YAAY,CAAC,CAAC,OAAO,EAAA,gBAAgB,CAAc,CAAC,CAAC,CAC5E,CAUA,eAAsB,EAAY,EAAgB,EAAiB,EAAyC,CAG3G,IAAM,EAAe,GAFC,EAAA,gBAAgB,IAAI,YAAY,CAAC,CAAC,OAAO,KAAK,UAAU,CAAM,CAAC,CAAC,CAAC,MAE/D,EAAc,GADf,EAAA,gBAAgB,IAAI,YAAY,CAAC,CAAC,OAAO,KAAK,UAAU,CAAO,CAAC,CAAC,CAAC,MAChD,IAEzC,GAAI,EAAY,CACf,IAAM,EAAY,MAAM,WAAW,OAAO,OAAO,KAChD,CACC,KAAM,QACN,KAAM,CAAE,KAAM,SAAU,CACzB,EACA,EACA,IAAI,YAAY,CAAC,CAAC,OAAO,CAAY,CACtC,EAEA,MAAO,GAAG,EAAa,GAAG,EAAA,gBAAgB,CAAS,GACpD,CAEA,MAAO,GAAG,EAAa,WACxB,CAaA,eAAsB,EAAc,CACnC,UACA,UACA,kBAAkB,GAClB,cACA,iBAO0B,CAC1B,IAAM,EAAW,MAAM,EAAqB,CAAO,EAC7C,EAAS,EAAkB,MAAM,EAAyB,CAAE,MAAO,EAAS,UAAS,QAAS,EAAS,QAAS,CAAC,EAAI,EAAyB,CAAO,EACrJ,EAAM,EAAA,UAAU,EAEtB,GAAI,GAAQ,MAAQ,EAAS,OAC5B,MAAM,IAAI,EAAA,cAAc,aAAa,EAEtC,GAAI,MAAM,QAAQ,GAAQ,GAAG,EAAI,CAAC,EAAO,IAAI,SAAS,EAAQ,QAAQ,EAAI,GAAQ,MAAQ,EAAQ,SACjG,MAAM,IAAI,EAAA,cAAc,aAAa,EAEtC,GAAI,CAAC,GAAQ,KAAO,EAAO,KAAO,EACjC,MAAM,IAAI,EAAA,cAAc,mBAAmB,EAE5C,GAAI,CAAC,GAAQ,KAAQ,GAAe,EAAO,MAAQ,EAClD,MAAM,IAAI,EAAA,cAAc,aAAa,EAEtC,GAAI,GAAiB,GAAQ,QAAU,EACtC,MAAM,IAAI,EAAA,cAAc,eAAe,EAGxC,OAAO,CACR,CAWA,eAAsB,EAAoF,CACzG,MACA,qBAAqB,GACrB,eAAe,GACf,SACA,WAOgB,CAChB,IAAM,EAAY,MAAM,EAAY,EAGpC,GAFA,EAAU,SAAW,CAAC,EAElB,CAAC,EAAK,CACT,IAAM,EAAW,MAAM,EAAqB,CAAO,EACnD,EAAM,IAAI,IAAI,EAAS,sBAAsB,CAC9C,CAKA,GAJI,OAAO,GAAQ,WAClB,EAAM,IAAI,IAAI,EAAK,WAAW,SAAS,MAAM,GAG1C,EAAoB,CACvB,IAAM,EAAS,IAAI,IAAI,EAAQ,QAAU,CAAC,QAAQ,CAAC,EAEnD,EAAI,aAAa,IAAI,YAAa,EAAQ,QAAQ,EAClD,EAAI,aAAa,IAAI,eAAgB,EAAQ,WAAW,EACxD,EAAI,aAAa,IAAI,gBAAiB,EAAQ,cAAgB,MAAM,EACpE,EAAI,aAAa,IAAI,gBAAiB,EAAQ,cAAgB,OAAO,EACrE,EAAI,aAAa,IAAI,QAAS,MAAM,KAAK,CAAM,CAAC,CAAC,KAAK,GAAG,CAAC,EAC1D,EAAI,aAAa,IAAI,wBAAyB,MAAM,EACpD,EAAI,aAAa,IAAI,QAAS,EAAU,EAAE,EAC1C,EAAI,aAAa,IAAI,iBAAkB,EAAU,aAAa,EAE1D,EAAO,IAAI,QAAQ,GACtB,EAAI,aAAa,IAAI,QAAS,EAAU,KAAK,CAE/C,CAcA,GAZI,EAAO,SACV,EAAI,aAAa,IAAI,SAAU,EAAO,MAAM,EAC5C,EAAU,SAAS,OAAS,EAAO,QAEhC,EAAO,UACV,EAAI,aAAa,IAAI,UAAW,EAAO,OAAO,EAC9C,EAAU,SAAS,QAAU,EAAO,SAEjC,EAAO,YACV,EAAI,aAAa,IAAI,aAAc,EAAO,SAAS,EACnD,EAAU,SAAS,UAAY,EAAO,WAEnC,EAAO,WAAW,OAAQ,CAC7B,IAAM,EAAY,EAAO,UAAU,OAAO,OAAO,EAE7C,EAAU,SACb,EAAI,aAAa,IAAI,aAAc,EAAU,KAAK,GAAG,CAAC,EACtD,EAAU,SAAS,UAAY,EAEjC,CACA,GAAI,EAAO,WAAW,OAAQ,CAC7B,IAAM,EAAY,EAAO,UAAU,OAAO,OAAO,EAE7C,EAAU,SACb,EAAI,aAAa,IAAI,aAAc,EAAU,KAAK,GAAG,CAAC,EACtD,EAAU,SAAS,UAAY,EAEjC,CACA,GAAI,EAAO,WAAW,OAAQ,CAC7B,IAAM,EAAY,EAAO,UAAU,OAAO,OAAO,EAE7C,EAAU,SACb,EAAI,aAAa,IAAI,WAAY,EAAU,KAAK,GAAG,CAAC,EACpD,EAAU,SAAS,UAAY,EAEjC,CAMA,OAJI,GACH,MAAM,EAAQ,aAAa,IAAI,OAAO,EAAU,KAAM,EAAe,CAAS,CAAC,EAGzE,CACR,CAYA,SAAgB,EAAmB,CAAE,MAAK,UAAS,yBAAsG,CACxJ,IAAM,EAAgB,IAAI,IAAI,CAAG,EAQjC,OANA,EAAc,aAAa,IAAI,gBAAiB,CAAO,EAEnD,GACH,EAAc,aAAa,IAAI,2BAA4B,CAAqB,EAG1E,CACR,CAiBA,eAAsB,EAAa,CAClC,MACA,SACA,WAKwB,CACxB,IAAM,EAAU,EAAA,cAAc,CAAM,EAEpC,GAAI,EAAQ,MACX,MAAM,IAAI,EAAA,UAAU,EAAQ,MAAO,EAAQ,kBAAmB,EAAQ,SAAS,EAEhF,GAAI,CAAC,EAAQ,KACZ,MAAM,IAAI,EAAA,cAAc,uCAAuC,EAGhE,IAAM,EAAW,OAAO,EAAQ,QAC1B,EAAkB,MAAM,EAAQ,aAAa,IAAI,CAAQ,EAE/D,GAAI,CAAC,EACJ,MAAM,IAAI,EAAA,cAAc,0BAA0B,EAGnD,IAAI,EAEJ,GAAI,CACH,EAAQ,EAAW,CAAe,CACnC,MAAQ,CACP,MAAM,IAAI,EAAA,cAAc,0BAA0B,CACnD,CAEA,MAAM,EAAQ,aAAa,OAAO,CAAQ,EAE1C,IAAM,EAAW,MAAM,EAAqB,CAAO,EAC7C,EAAW,GAAO,EAAS,eAC3B,EAAW,MAAM,EAAQ,WAAW,iBAAyC,EAAU,CAC5F,WAAY,qBACZ,UAAW,EAAQ,SACnB,aAAc,EAAQ,YACtB,cAAe,EAAM,aACrB,KAAM,EAAQ,IACf,CAAC,EAEI,EAAS,IACb,MAAM,EAAA,wBAAwB,CAAQ,EAGvC,IAAI,EAEJ,GAAI,CACH,EAAO,MAAM,EAAS,KAAK,CAC5B,MAAQ,CACP,MAAM,IAAI,EAAA,cAAc,uCAAuC,CAChE,CAEA,IAAM,EAA8B,CAAE,GAAG,EAAQ,GAAG,EAAA,cAAc,CAAI,CAAE,EAExE,GAAI,EAAe,MAClB,MAAM,IAAI,EAAA,UAAU,EAAe,MAAO,EAAe,kBAAmB,EAAe,SAAS,EAOrG,OAJI,EAAe,WAClB,EAAe,OAAS,MAAM,EAAc,CAAE,QAAS,EAAe,SAAU,cAAe,EAAM,MAAO,SAAQ,CAAC,GAG/G,CACR,CAmBA,eAAsB,EAAa,CAClC,MACA,eACA,UACA,YAAY,gBACZ,WACA,WACA,QACA,eAUwB,CACxB,IAAM,EAAiC,CACtC,WAAY,EACZ,UAAW,GAAY,EAAQ,SAC/B,cAAe,CAChB,EAEI,IACH,EAAO,SAAW,GAGf,IACH,EAAO,MAAQ,GAGhB,IAAM,EAAW,MAAM,EAAqB,CAAO,EAC7C,EAAa,GAAO,EAAS,eAC7B,EAAW,MAAM,EAAQ,WAAW,iBAAyC,EAAY,CAAM,EAEhG,EAAS,IACb,MAAM,EAAA,wBAAwB,CAAQ,EAGvC,IAAI,EAEJ,GAAI,CACH,EAAO,MAAM,EAAS,KAAK,CAC5B,MAAQ,CACP,MAAM,IAAI,EAAA,cAAc,uCAAuC,CAChE,CAEA,IAAM,EAA8B,EAAA,cAAc,CAAI,EAEtD,GAAI,EAAe,MAClB,MAAM,IAAI,EAAA,UAAU,EAAe,MAAO,EAAe,kBAAmB,EAAe,SAAS,EAOrG,OAJI,EAAe,WAClB,EAAe,OAAS,MAAM,EAAc,CAAE,QAAS,EAAe,SAAU,cAAa,SAAQ,CAAC,GAGhG,CACR,CAeA,eAAsB,EAAY,CACjC,MACA,gBACA,QACA,UACA,YAOiB,CACjB,IAAM,EAAW,MAAM,EAAqB,CAAO,EAC7C,EAAY,GAAO,EAAS,oBAElC,GAAI,CAAC,EAAW,CACf,EAAQ,SAAS,MAAM,sDAAsD,EAC7E,MACD,CAEA,IAAM,EAAW,MAAM,EAAQ,WAAW,iBAAyC,EAAW,CAC7F,UAAW,GAAY,EAAQ,SAC/B,gBAAiB,EACjB,OACD,CAAC,EAEG,GAAY,CAAC,EAAS,IACzB,MAAM,EAAA,wBAAwB,CAAQ,CAExC,CAiBA,eAAsB,EAAe,CACpC,MACA,SACA,UACA,WACA,cACA,UAAU,OAQgB,CAC1B,EAAO,IAAI,MAAO,CAAO,EACzB,EAAO,IAAI,YAAa,GAAY,EAAQ,QAAQ,EACpD,EAAO,IAAI,eAAgB,GAAe,EAAQ,WAAW,EAE7D,IAAM,EAAa,IAAI,IAAI,CAAG,EAC9B,EAAW,OAAS,EAAO,SAAS,EAEpC,IAAM,EAAW,MAAM,EAAQ,WAAW,QAAyC,CAAU,EAE7F,GAAI,CAAC,EAAS,GAAI,CACjB,GAAI,EAAS,SAAW,IAAK,CAC5B,IAAM,EAAO,MAAM,EAAS,KAAK,EAEjC,GAAI,GAAQ,OAAO,GAAS,SAAU,CACrC,GAAI,EAAK,MACR,MAAM,IAAI,EAAA,UAAU,EAAK,MAAO,EAAK,kBAAmB,EAAK,SAAS,EAChE,GAAI,EAAK,SACf,MAAM,IAAI,EAAA,cAAc,EAAK,QAAQ,CAEvC,CAEA,MAAM,IAAI,EAAA,cAAc,sBAAsB,CAC/C,CAEA,EAAA,eAAe,EAAS,OAAQ,sBAAsB,CACvD,CAEA,IAAI,EACA,EAEJ,GAAI,CACH,EAAM,IAAI,IAAI,MAAM,EAAS,KAAK,CAAC,EACnC,EAAe,OAAO,YAAY,EAAI,aAAa,QAAQ,CAAC,CAC7D,MAAQ,CACP,EAAM,IAAI,IAAI,EAAS,GAAG,EAC1B,EAAe,OAAO,YAAY,EAAI,aAAa,QAAQ,CAAC,CAC7D,CAEA,IAAM,EAAa,EAAa,aAC1B,EAAY,EAAa,WACzB,EAAW,EAAa,UAAY,WAAW,WAAW,UAAY,QAE5E,GAAI,CAAC,EACJ,MAAM,IAAI,EAAA,cAAc,2CAA2C,EAGpE,MAAO,CAAE,WAAY,EAAW,aAAc,EAAY,UAAS,CACpE,CAcA,eAAsB,EAAqB,CAC1C,MACA,YACA,WACA,WAMgB,CAChB,IAAM,EAAW,MAAM,EAAQ,WAAW,QAAQ,EAAK,CACtD,OAAQ,MACR,YAAa,UACb,QAAS,CACR,cAAe,UAAU,IACzB,kBAAmB,CACpB,CACD,CAAC,EAEI,EAAS,IACb,EAAA,eAAe,EAAS,OAAQ,kCAAkC,EAGnE,IAAI,EAEJ,GAAI,CACH,EAAc,IAAI,IAAI,MAAM,EAAS,KAAK,CAAC,CAC5C,MAAQ,CACP,MAAM,IAAI,EAAA,cAAc,sBAAsB,CAC/C,CAEA,GAAI,CAAC,EAAY,SAAS,CAAC,CAAC,WAAW,EAAQ,WAAW,EACzD,MAAM,IAAI,EAAA,cAAc,sBAAsB,EAG/C,OAAO,CACR,CAgBA,eAAsB,EAAgB,CACrC,SACA,OACA,YACA,WACA,WAO4B,CAC5B,IAAM,EAAW,MAAM,EAAQ,WAAW,QAAyB,IAAI,IAAI,gBAAgB,EAAS,QAAQ,IAAW,SAAU,EAAQ,MAAM,EAAG,CACjJ,OAAQ,OACR,YAAa,UACb,KAAM,KAAK,UAAU,CAAI,EACzB,QAAS,CACR,cAAe,UAAU,IACzB,eAAgB,mBAChB,kBAAmB,CACpB,CACD,CAAC,EACG,EAAwB,CAAC,EAE7B,GAAI,CACH,EAAO,MAAM,EAAS,KAAK,CAC5B,MAAQ,CAAC,CAET,GAAI,CAAC,EAAS,GAAI,CACjB,GAAI,EAAS,SAAW,IACvB,MAAM,IAAI,EAAA,oBAGX,GAAI,EAAS,QAAU,KAAO,EAAS,OAAS,KAAO,GAAM,WAAa,CAAC,EAAK,SAC/E,MAAM,IAAI,EAAA,cAAc,IAAI,IAAI,EAAK,SAAS,EAAG,iBAAiB,EAAS,OAAO,kBAAkB,EAGrG,EAAA,eAAe,EAAS,OAAQ,6BAA6B,CAC9D,CAEA,GAAI,EAAK,WAAa,CAAC,EAAK,aAAe,CAAC,EAAK,OAAS,CAAC,EAAK,SAC/D,MAAM,IAAI,EAAA,cAAc,IAAI,IAAI,EAAK,SAAS,EAAG,kCAAkC,EAGpF,OAAO,CACR"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{FallbackError as e,NetworkError as t,OidcError as n,ProtocolError as r,ServerError as i,SessionExpiredError as a,throwHttpError as o,throwTokenEndpointError as s}from"../utils/errors.mjs";import{decodeBase64URL as c,encodeBase64URL as l}from"../utils/base64url.mjs";import{createHttpClient as u}from"../utils/httpClient.mjs";import{timestamp as d}from"../utils/common.mjs";import{createSession as f}from"../utils/session.mjs";import{redirectCallbackHandler as p,redirectUrlHandler as m}from"../handlers/redirect.mjs";import{createLocalStorage as h}from"../storages/local.mjs";import{createSessionStorage as g}from"../storages/session.mjs";async function _(e={}){let t=k();return{id:j(16),createdAt:d(),codeVerifier:t,metadata:e,codeChallenge:await A(t),nonce:j(16)}}function v(e){return JSON.parse(e)}function y(e){return JSON.stringify(e)}var b=0,x=null,S=null,C=new Map;function w(){return{initialized:!1,session:null,sessionId:null,shortAppId:null,language:globalThis.navigator?.language??`en-US`}}var T={lazyLoad:!1,autoRefresh:!0,serverSessionUri:null,scopes:[`openid`],responseType:`code`,responseMode:`query`,storageTokenName:`sty.session`,discoveryDocumentCacheTTL:3600,jwksCacheTTL:600};async function E(e){return S&&b>d()?S:x||(x=(async()=>{try{let t=await e.httpClient.request(new URL(`/.well-known/openid-configuration`,e.issuer));if(!t.ok)throw new i(`Failed to fetch OIDC metadata`,t.status);let n;try{n=await t.json()}catch{throw new r(`Non-JSON response from discovery document endpoint`)}if(n.issuer?.replace(/\/$/,``)!==e.issuer.replace(/\/$/,``))throw new r(`Discovery document issuer mismatch: expected ${e.issuer}, got ${n.issuer}`);let a=new URL(e.issuer).host;for(let e of[`authorization_endpoint`,`token_endpoint`,`jwks_uri`]){let t=n[e];if(!t)throw new r(`Discovery document is missing required field: ${e}`);let i=new URL(t);if(i.protocol!==`https:`||i.host!==a)throw new r(`Discovery document field "${e}" must be an https:// URL on ${a}, got ${t}`)}for(let e of[`end_session_endpoint`,`revocation_endpoint`]){let t=n[e];if(!t)continue;let i=new URL(t);if(i.protocol!==`https:`||i.host!==a)throw new r(`Discovery document field "${e}" must be an https:// URL on ${a}, got ${t}`)}if(!n.code_challenge_methods_supported?.includes(`S256`))throw new r(`Discovery document does not advertise S256 PKCE support`);return S=n,b=d()+e.discoveryDocumentCacheTTL,n}finally{x=null}})(),x)}async function D({jwksUri:e,options:n,forceRefresh:r=!1}){let a=C.get(e);if(!r&&a&&a.expiresAt>d())return{keys:a.keys};let o;try{o=await fetch(e)}catch{throw new t(`Failed to fetch JWKS: ${e}`)}if(!o.ok)throw new i(`Failed to fetch JWKS: HTTP ${o.status}`,o.status);let s=await o.json();return C.set(e,{keys:s.keys,expiresAt:d()+n.jwksCacheTTL}),s}function O(e){return e.issuer=e.issuer.endsWith(`/`)?e.issuer.slice(0,-1):e.issuer,e.storage??=h(),e.stateStorage??=g(),e.httpClient??=u(e.logging),e.urlHandler??=m,e.callbackHandler??=p,e.lazyLoad??=T.lazyLoad,e.autoRefresh??=T.autoRefresh,e.serverSessionUri??=T.serverSessionUri,e.scopes??=T.scopes,e.responseType??=T.responseType,e.responseMode??=T.responseMode,e.storageTokenName??=T.storageTokenName,e.discoveryDocumentCacheTTL??=T.discoveryDocumentCacheTTL,e.jwksCacheTTL??=T.jwksCacheTTL,e}function k(){let e=new Uint8Array(32);return globalThis.crypto.getRandomValues(e),l(e.buffer)}async function A(e){let t=new TextEncoder().encode(e),n=await globalThis.crypto.subtle.digest(`SHA-256`,t);return l(n)}function j(e=16){let t=new Uint8Array(e);return globalThis.crypto.getRandomValues(t),Array.from(t).map(e=>e.toString(16).padStart(2,`0`)).join(``)}function M(e){let[,t]=e.split(`.`);if(!t)throw new r(`Invalid JWT: missing payload segment`);try{return JSON.parse(new TextDecoder().decode(c(t)))}catch{throw new r(`Invalid JWT: payload is not valid base64url-encoded JSON`)}}async function N({token:e,jwksUri:t,options:n}){let i=e.split(`.`);if(i.length!==3)throw new r(`Invalid JWT: must have 3 parts`);let[a,o,s]=i,l=JSON.parse(new TextDecoder().decode(c(a)));if(l.alg!==`RS256`)throw new r(`Unsupported JWT algorithm: ${l.alg}`);let u=await D({jwksUri:t,options:n}),d=l.kid?u.keys.find(e=>e.kid===l.kid):u.keys.find(e=>e.alg===`RS256`);if(!d&&l.kid&&(u=await D({jwksUri:t,options:n,forceRefresh:!0}),d=u.keys.find(e=>e.kid===l.kid)),!d)throw new r(`No matching key found in JWKS${l.kid?` for kid: ${l.kid}`:``}`);let f=await globalThis.crypto.subtle.importKey(`jwk`,{kty:d.kty,n:d.n,e:d.e,alg:d.alg,use:d.use},{name:`RSASSA-PKCS1-v1_5`,hash:{name:`SHA-256`}},!1,[`verify`]),p=c(s),m=new TextEncoder().encode(`${a}.${o}`);if(!await globalThis.crypto.subtle.verify({name:`RSASSA-PKCS1-v1_5`},f,p,m))throw new r(`JWT signature verification failed`);return JSON.parse(new TextDecoder().decode(c(o)))}async function P(e,t,n){let r=`${l(new TextEncoder().encode(JSON.stringify(e)).buffer)}.${l(new TextEncoder().encode(JSON.stringify(t)).buffer)}`;if(n){let e=await globalThis.crypto.subtle.sign({name:`ECDSA`,hash:{name:`SHA-256`}},n,new TextEncoder().encode(r));return`${r}.${l(e)}`}return`${r}.signature`}async function F({idToken:e,options:t,verifySignature:n=!1,expectedSub:i,expectedNonce:a}){let o=await E(t),s=n?await N({token:e,options:t,jwksUri:o.jwks_uri}):M(e),c=d();if(s?.iss!==o.issuer)throw new r(`Invalid iss`);if(Array.isArray(s?.aud)?!s.aud.includes(t.clientId):s?.aud!==t.clientId)throw new r(`Invalid aud`);if(!s?.exp||s.exp<=c)throw new r(`Token has expired`);if(!s?.sub||i&&s.sub!==i)throw new r(`Invalid sub`);if(a&&s?.nonce!==a)throw new r(`Invalid nonce`);return s}async function I({url:e,includeOAuthParams:t=!0,persistState:n=!0,params:r,options:i}){let a=await _();if(a.metadata={},!e){let t=await E(i);e=new URL(t.authorization_endpoint)}if(typeof e==`string`&&(e=new URL(e,globalThis.location.origin)),t){let t=new Set(i.scopes??[`openid`]);e.searchParams.set(`client_id`,i.clientId),e.searchParams.set(`redirect_uri`,i.redirectUri),e.searchParams.set(`response_type`,i.responseType??`code`),e.searchParams.set(`response_mode`,i.responseMode??`query`),e.searchParams.set(`scope`,Array.from(t).join(` `)),e.searchParams.set(`code_challenge_method`,`S256`),e.searchParams.set(`state`,a.id),e.searchParams.set(`code_challenge`,a.codeChallenge),t.has(`openid`)&&e.searchParams.set(`nonce`,a.nonce)}if(r.prompt&&(e.searchParams.set(`prompt`,r.prompt),a.metadata.prompt=r.prompt),r.display&&(e.searchParams.set(`display`,r.display),a.metadata.display=r.display),r.loginHint&&(e.searchParams.set(`login_hint`,r.loginHint),a.metadata.loginHint=r.loginHint),r.acrValues?.length){let t=r.acrValues.filter(Boolean);t.length&&(e.searchParams.set(`acr_values`,t.join(` `)),a.metadata.acrValues=t)}if(r.uiLocales?.length){let t=r.uiLocales.filter(Boolean);t.length&&(e.searchParams.set(`ui_locales`,t.join(` `)),a.metadata.uiLocales=t)}if(r.audiences?.length){let t=r.audiences.filter(Boolean);t.length&&(e.searchParams.set(`audience`,t.join(` `)),a.metadata.audiences=t)}return n&&await i.stateStorage.set(`sty.${a.id}`,y(a)),e}function L({url:e,idToken:t,postLogoutRedirectUri:n}){let r=new URL(e);return r.searchParams.set(`id_token_hint`,t),n&&r.searchParams.set(`post_logout_redirect_uri`,n),r}async function R({url:e,params:t,options:i}){let a=f(t);if(a.error)throw new n(a.error,a.error_description,a.error_uri);if(!a.code)throw new r(`Invalid or missing authorization code`);let o=`sty.${a.state}`,c=await i.stateStorage.get(o);if(!c)throw new r(`Invalid or missing state`);let l;try{l=v(c)}catch{throw new r(`Invalid or missing state`)}await i.stateStorage.delete(o);let u=await E(i),d=e??u.token_endpoint,p=await i.httpClient.sendTokenRequest(d,{grant_type:`authorization_code`,client_id:i.clientId,redirect_uri:i.redirectUri,code_verifier:l.codeVerifier,code:a.code});p.ok||await s(p);let m;try{m=await p.json()}catch{throw new r(`Non-JSON response from token endpoint`)}let h={...t,...f(m)};if(h.error)throw new n(h.error,h.error_description,h.error_uri);return h.id_token&&(h.claims=await F({idToken:h.id_token,expectedNonce:l.nonce,options:i})),h}async function z({url:e,refreshToken:t,options:i,grantType:a=`refresh_token`,clientId:o,audience:c,scope:l,expectedSub:u}){let d={grant_type:a,client_id:o??i.clientId,refresh_token:t};c&&(d.audience=c),l&&(d.scope=l);let p=await E(i),m=e??p.token_endpoint,h=await i.httpClient.sendTokenRequest(m,d);h.ok||await s(h);let g;try{g=await h.json()}catch{throw new r(`Non-JSON response from token endpoint`)}let _=f(g);if(_.error)throw new n(_.error,_.error_description,_.error_uri);return _.id_token&&(_.claims=await F({idToken:_.id_token,expectedSub:u,options:i})),_}async function B({url:e,tokenTypeHint:t,token:n,options:r,clientId:i}){let a=await E(r),o=e??a.revocation_endpoint;if(!o){r.logging?.debug(`Revocation skipped: no revocation_endpoint available`);return}let c=await r.httpClient.sendTokenRequest(o,{client_id:i??r.clientId,token_type_hint:t,token:n});c&&!c.ok&&await s(c)}async function V({url:e,params:t,options:i,clientId:a,redirectUri:s,sdkMode:c=`web`}){t.set(`sdk`,c),t.set(`client_id`,a??i.clientId),t.set(`redirect_uri`,s??i.redirectUri);let l=new URL(e);l.search=t.toString();let u=await i.httpClient.request(l);if(!u.ok){if(u.status===400){let e=await u.json();if(e&&typeof e==`object`){if(e.error)throw new n(e.error,e.error_description,e.error_uri);if(e.errorKey)throw new r(e.errorKey)}throw new r(`Entry request failed`)}o(u.status,`Entry request failed`)}let d,f;try{d=new URL(await u.text()),f=Object.fromEntries(d.searchParams.entries())}catch{d=new URL(u.url),f=Object.fromEntries(d.searchParams.entries())}let p=f.short_app_id,m=f.session_id,h=f.language||globalThis.navigator?.language||`en-US`;if(!m)throw new r(`"session_id" is missing from the response`);return{session_id:m,short_app_id:p,language:h}}async function H({url:e,sessionId:t,language:n,options:i}){let a=await i.httpClient.request(e,{method:`GET`,credentials:`include`,headers:{Authorization:`Bearer ${t}`,"Accept-language":n}});a.ok||o(a.status,`Failed to finalize login session`);let s;try{s=new URL(await a.text())}catch{throw new r(`Invalid redirect URI`)}if(!s.toString().startsWith(i.redirectUri))throw new r(`Invalid redirect URI`);return s}async function U({formId:t,body:n,sessionId:r,language:i,options:s}){let c=await s.httpClient.request(new URL(`/flow/api/v1/${t?`form/${t}`:`init`}`,s.issuer),{method:`POST`,credentials:`include`,body:JSON.stringify(n),headers:{Authorization:`Bearer ${r}`,"Content-Type":`application/json`,"Accept-language":i}}),l={};try{l=await c.json()}catch{}if(!c.ok){if(c.status===403)throw new a;if(c.status>=400&&c.status<500&&l?.hostedUrl&&!l.messages)throw new e(new URL(l.hostedUrl),`Received HTTP ${c.status} without messages`);o(c.status,`Failed to submit login form`)}if(l.hostedUrl&&!l.finalizeUrl&&!l.forms&&!l.messages)throw new e(new URL(l.hostedUrl),`No forms or messages in response`);return l}export{y as S,U as _,R as a,_ as b,A as c,j as d,w as f,B as g,z as h,T as i,k as l,O as m,L as n,V as o,E as p,M as r,H as s,I as t,P as u,F as v,v as x,N as y};
|
|
2
|
+
//# sourceMappingURL=oidc.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oidc.mjs","names":[],"sources":["../../src/utils/state.ts","../../src/utils/oidc.ts"],"sourcesContent":["import type { StateData } from '../types/oidc';\nimport { timestamp } from './common';\nimport { generateCodeVerifier, generateCodeChallenge, generateRandomHex } from './oidc';\n\n/**\n * Creates a new state object for OAuth 2.0 authorization requests, including a code verifier and challenge for PKCE.\n *\n * @param {Record<string, unknown>} [metadata={}] Optional metadata to associate with the state.\n * @returns {Promise<StateData>} A promise that resolves to the newly created state object.\n */\nexport async function createState(metadata: Record<string, unknown> = {}): Promise<StateData> {\n\tconst codeVerifier = generateCodeVerifier();\n\n\treturn {\n\t\tid: generateRandomHex(16),\n\t\tcreatedAt: timestamp(),\n\t\tcodeVerifier,\n\t\tmetadata,\n\t\tcodeChallenge: await generateCodeChallenge(codeVerifier),\n\t\tnonce: generateRandomHex(16),\n\t};\n}\n\n/**\n * Parses a serialized state string into a StateData object.\n *\n * @param {string} serialized - The serialized state string to parse.\n * @returns {StateData} The parsed StateData object.\n * @throws {Error} If the serialized string is invalid or cannot be parsed.\n */\nexport function parseState(serialized: string): StateData {\n\treturn JSON.parse(serialized) as StateData;\n}\n\n/**\n * Serializes a StateData object into a string for storage or transmission.\n *\n * @param {StateData} state - The StateData object to serialize.\n * @returns {string} The serialized state string.\n */\nexport function serializeState(state: StateData): string {\n\treturn JSON.stringify(state);\n}\n","import type { ExtraRequestArgs, IdTokenClaims, DiscoveryDocument, SDKOptions, SessionData, EntryResponse, FlowState, SigningKey } from '../types/oidc';\nimport type { NativeFlowState } from '../types/native';\nimport { decodeBase64URL, encodeBase64URL } from './base64url';\nimport { FallbackError, SessionExpiredError, OidcError, ProtocolError, ServerError, NetworkError, throwHttpError, throwTokenEndpointError } from './errors';\nimport { createHttpClient } from './httpClient';\nimport { createSession } from './session';\nimport { createState, parseState, serializeState } from './state';\nimport { redirectUrlHandler, redirectCallbackHandler } from '../handlers/redirect';\nimport { createLocalStorage } from '../storages/local';\nimport { createSessionStorage } from '../storages/session';\nimport { timestamp } from './common';\n\n/**\n * Stores the expiration timestamp of the cached OpenID configuration discovery document.\n */\nlet discoveryDocumentCacheExpiresAt = 0;\n\n/**\n * A promise that represents the ongoing fetch of the OpenID configuration discovery document.\n */\nlet discoveryDocumentFetchPromise: Promise<DiscoveryDocument> | null = null;\n\n/**\n * OpenID configuration discovery document cache.\n */\nlet discoveryDocument: DiscoveryDocument | null = null;\n\n/**\n * JSON Web Key Set (JWKS) cache.\n */\nconst jwksCache = new Map<string, { keys: Array<SigningKey>; expiresAt: number }>();\n\n/**\n * Returns the default flow state for the SDK.\n *\n * @returns {FlowState} The default flow state object.\n */\nexport function getDefaultFlowState(): FlowState {\n\treturn {\n\t\tinitialized: false,\n\t\tsession: null,\n\t\tsessionId: null,\n\t\tshortAppId: null,\n\t\tlanguage: globalThis.navigator?.language ?? 'en-US',\n\t};\n}\n\n/**\n * Returns the default SDK options for the SDK.\n */\nexport const defaultOptions: Partial<SDKOptions> = {\n\tlazyLoad: false,\n\tautoRefresh: true,\n\tserverSessionUri: null,\n\tscopes: ['openid'],\n\tresponseType: 'code',\n\tresponseMode: 'query',\n\tstorageTokenName: 'sty.session',\n\tdiscoveryDocumentCacheTTL: 3600,\n\tjwksCacheTTL: 600,\n} as const;\n\n/**\n * Fetches the OpenID configuration discovery document from the authorization server.\n * Caches the document for a specified duration to avoid unnecessary network requests.\n *\n * @param {SDKOptions} options - The SDK options containing the issuer URL and other configurations.\n * @returns {Promise<DiscoveryDocument>} A promise that resolves to the fetched discovery document.\n * @throws {ServerError} If the discovery document fetch fails with a server error (HTTP 429 or 5xx).\n * @throws {ProtocolError} If the discovery document is missing required fields or has an issuer mismatch.\n */\nexport async function getDiscoveryDocument(options: SDKOptions): Promise<DiscoveryDocument> {\n\tif (discoveryDocument && discoveryDocumentCacheExpiresAt > timestamp()) {\n\t\treturn discoveryDocument;\n\t}\n\n\tif (discoveryDocumentFetchPromise) {\n\t\treturn discoveryDocumentFetchPromise;\n\t}\n\n\tdiscoveryDocumentFetchPromise = (async () => {\n\t\ttry {\n\t\t\tconst response = await options.httpClient.request<DiscoveryDocument>(new URL('/.well-known/openid-configuration', options.issuer));\n\n\t\t\tif (!response.ok) {\n\t\t\t\tthrow new ServerError(`Failed to fetch OIDC metadata`, response.status);\n\t\t\t}\n\n\t\t\tlet metadata: DiscoveryDocument;\n\n\t\t\ttry {\n\t\t\t\tmetadata = await response.json();\n\t\t\t} catch {\n\t\t\t\tthrow new ProtocolError('Non-JSON response from discovery document endpoint');\n\t\t\t}\n\n\t\t\tif (metadata.issuer?.replace(/\\/$/, '') !== options.issuer.replace(/\\/$/, '')) {\n\t\t\t\tthrow new ProtocolError(`Discovery document issuer mismatch: expected ${options.issuer}, got ${metadata.issuer}`);\n\t\t\t}\n\n\t\t\tconst issuerHost = new URL(options.issuer).host;\n\n\t\t\tfor (const field of ['authorization_endpoint', 'token_endpoint', 'jwks_uri'] as const) {\n\t\t\t\tconst endpoint = metadata[field];\n\n\t\t\t\tif (!endpoint) {\n\t\t\t\t\tthrow new ProtocolError(`Discovery document is missing required field: ${field}`);\n\t\t\t\t}\n\n\t\t\t\tconst endpointUrl = new URL(endpoint);\n\n\t\t\t\tif (endpointUrl.protocol !== 'https:' || endpointUrl.host !== issuerHost) {\n\t\t\t\t\tthrow new ProtocolError(`Discovery document field \"${field}\" must be an https:// URL on ${issuerHost}, got ${endpoint}`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (const field of ['end_session_endpoint', 'revocation_endpoint'] as const) {\n\t\t\t\tconst endpoint = metadata[field];\n\n\t\t\t\tif (!endpoint) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst endpointUrl = new URL(endpoint);\n\n\t\t\t\tif (endpointUrl.protocol !== 'https:' || endpointUrl.host !== issuerHost) {\n\t\t\t\t\tthrow new ProtocolError(`Discovery document field \"${field}\" must be an https:// URL on ${issuerHost}, got ${endpoint}`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!metadata.code_challenge_methods_supported?.includes('S256')) {\n\t\t\t\tthrow new ProtocolError('Discovery document does not advertise S256 PKCE support');\n\t\t\t}\n\n\t\t\tdiscoveryDocument = metadata;\n\t\t\tdiscoveryDocumentCacheExpiresAt = timestamp() + options.discoveryDocumentCacheTTL;\n\n\t\t\treturn metadata;\n\t\t} finally {\n\t\t\tdiscoveryDocumentFetchPromise = null;\n\t\t}\n\t})();\n\n\treturn discoveryDocumentFetchPromise;\n}\n\n/**\n * Returns the JWKS for the given URI, from cache unless it's stale or `forceRefresh` is set.\n *\n * @param {Object} options - The options for fetching the JWKS.\n * @param {string} options.jwksUri - The URL of the JWKS endpoint.\n * @param {SDKOptions} options.options - The SDK options containing client ID, storage, and other options.\n * @param {boolean} [options.forceRefresh=false] - Bypasses the cache and fetches a fresh key set.\n * @returns {Promise<{ keys: Array<SigningKey> }>} The (possibly cached) key set.\n * @throws {NetworkError} If the JWKS fetch fails due to network issues.\n * @throws {ServerError} If the JWKS fetch fails with a server error (HTTP 429 or 5xx).\n */\nasync function getJwks({\n\tjwksUri,\n\toptions,\n\tforceRefresh = false,\n}: {\n\tjwksUri: string;\n\toptions: SDKOptions;\n\tforceRefresh?: boolean;\n}): Promise<{ keys: Array<SigningKey> }> {\n\tconst cached = jwksCache.get(jwksUri);\n\n\tif (!forceRefresh && cached && cached.expiresAt > timestamp()) {\n\t\treturn { keys: cached.keys };\n\t}\n\n\tlet jwksResponse: Response;\n\n\ttry {\n\t\tjwksResponse = await fetch(jwksUri);\n\t} catch {\n\t\tthrow new NetworkError(`Failed to fetch JWKS: ${jwksUri}`);\n\t}\n\n\tif (!jwksResponse.ok) {\n\t\tthrow new ServerError(`Failed to fetch JWKS: HTTP ${jwksResponse.status}`, jwksResponse.status);\n\t}\n\n\tconst jwks = (await jwksResponse.json()) as { keys: Array<SigningKey> };\n\n\tjwksCache.set(jwksUri, { keys: jwks.keys, expiresAt: timestamp() + options.jwksCacheTTL });\n\n\treturn jwks;\n}\n\n/**\n * Returns with the SDK options merged with the provided options.\n *\n * @param {SDKInitConfig} options - The SDK initialization configuration.\n * @template InitOptions - The type of the SDK initialization configuration.\n * @template Options - The type of the SDK options.\n * @returns {Options} The merged SDK options.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function getSDKOptions<Options extends SDKOptions = SDKOptions>(options: any): Options {\n\toptions.issuer = options.issuer.endsWith('/') ? options.issuer.slice(0, -1) : options.issuer;\n\toptions.storage ??= createLocalStorage();\n\toptions.stateStorage ??= createSessionStorage();\n\toptions.httpClient ??= createHttpClient(options.logging);\n\toptions.urlHandler ??= redirectUrlHandler;\n\toptions.callbackHandler ??= redirectCallbackHandler;\n\toptions.lazyLoad ??= defaultOptions.lazyLoad;\n\toptions.autoRefresh ??= defaultOptions.autoRefresh;\n\toptions.serverSessionUri ??= defaultOptions.serverSessionUri;\n\n\toptions.scopes ??= defaultOptions.scopes;\n\toptions.responseType ??= defaultOptions.responseType;\n\toptions.responseMode ??= defaultOptions.responseMode;\n\toptions.storageTokenName ??= defaultOptions.storageTokenName;\n\toptions.discoveryDocumentCacheTTL ??= defaultOptions.discoveryDocumentCacheTTL;\n\toptions.jwksCacheTTL ??= defaultOptions.jwksCacheTTL;\n\n\treturn options;\n}\n\n/**\n * Generates a code verifier for PKCE (Proof Key for Code Exchange).\n *\n * @returns {string} A randomly generated code verifier string.\n */\nexport function generateCodeVerifier(): string {\n\tconst bytes = new Uint8Array(32);\n\n\tglobalThis.crypto.getRandomValues(bytes);\n\n\treturn encodeBase64URL(bytes.buffer);\n}\n\n/**\n * Generates a code challenge from a code verifier using SHA-256 hashing.\n *\n * @param {string} codeVerifier The code verifier string.\n * @returns {Promise<string>} A promise that resolves to the generated code challenge.\n */\nexport async function generateCodeChallenge(codeVerifier: string): Promise<string> {\n\tconst encoded = new TextEncoder().encode(codeVerifier);\n\tconst hash = await globalThis.crypto.subtle.digest('SHA-256', encoded);\n\n\treturn encodeBase64URL(hash);\n}\n\n/**\n * Generates a random hexadecimal string of the specified byte length.\n *\n * @param {number} [byteLength=16] - The number of random bytes to generate (default is 16).\n * @returns {string} A randomly generated hexadecimal string.\n */\nexport function generateRandomHex(byteLength = 16): string {\n\tconst bytes = new Uint8Array(byteLength);\n\n\tglobalThis.crypto.getRandomValues(bytes);\n\n\treturn Array.from(bytes)\n\t\t.map((b) => b.toString(16).padStart(2, '0'))\n\t\t.join('');\n}\n\n/**\n * Decodes a JWT token and returns the payload as an object.\n *\n * @template T The expected structure of the JWT payload.\n * @param {string} token - The JWT token to decode.\n * @returns {T} The decoded payload of the JWT token.\n * @throws {ProtocolError} If the token is invalid or has the wrong format.\n */\nexport function decodeJwt<T = Record<string, unknown>>(token: string): T {\n\tconst [, payload] = token.split('.');\n\n\tif (!payload) {\n\t\tthrow new ProtocolError('Invalid JWT: missing payload segment');\n\t}\n\n\ttry {\n\t\treturn JSON.parse(new TextDecoder().decode(decodeBase64URL(payload))) as T;\n\t} catch {\n\t\tthrow new ProtocolError('Invalid JWT: payload is not valid base64url-encoded JSON');\n\t}\n}\n\n/**\n * Verifies a JWT token's signature against a JWKS endpoint.\n * Only RS256 is supported.\n *\n * @param {Object} options - The options for verifying the JWT.\n * @param {string} options.token - The JWT token to verify.\n * @param {string} options.jwksUri - The URL of the JWKS endpoint.\n * @param {SDKOptions} options.options - The SDK options containing client ID, storage, and other options.\n * @template T - The expected structure of the JWT payload.\n * @returns {Promise<T>} The verified payload.\n * @throws {ProtocolError} If the token is invalid, the key is not found, or verification fails.\n */\nexport async function verifyJwt<T = Record<string, unknown>>({ token, jwksUri, options }: { token: string; jwksUri: string; options: SDKOptions }): Promise<T> {\n\tconst parts = token.split('.');\n\n\tif (parts.length !== 3) {\n\t\tthrow new ProtocolError('Invalid JWT: must have 3 parts');\n\t}\n\n\tconst [encodedHeader, encodedPayload, encodedSignature] = parts;\n\tconst header = JSON.parse(new TextDecoder().decode(decodeBase64URL(encodedHeader))) as { kid?: string; alg?: string };\n\n\tif (header.alg !== 'RS256') {\n\t\tthrow new ProtocolError(`Unsupported JWT algorithm: ${header.alg}`);\n\t}\n\n\tlet jwks = await getJwks({ jwksUri, options });\n\tlet signingKey = header.kid ? jwks.keys.find((k) => k.kid === header.kid) : jwks.keys.find((k) => k.alg === 'RS256');\n\n\tif (!signingKey && header.kid) {\n\t\tjwks = await getJwks({ jwksUri, options, forceRefresh: true });\n\t\tsigningKey = jwks.keys.find((k) => k.kid === header.kid);\n\t}\n\n\tif (!signingKey) {\n\t\tthrow new ProtocolError(`No matching key found in JWKS${header.kid ? ` for kid: ${header.kid}` : ''}`);\n\t}\n\n\tconst cryptoKey = await globalThis.crypto.subtle.importKey(\n\t\t'jwk',\n\t\t{ kty: signingKey.kty, n: signingKey.n, e: signingKey.e, alg: signingKey.alg, use: signingKey.use },\n\t\t{ name: 'RSASSA-PKCS1-v1_5', hash: { name: 'SHA-256' } },\n\t\tfalse,\n\t\t['verify'],\n\t);\n\tconst signature = decodeBase64URL(encodedSignature);\n\tconst data = new TextEncoder().encode(`${encodedHeader}.${encodedPayload}`);\n\tconst valid = await globalThis.crypto.subtle.verify({ name: 'RSASSA-PKCS1-v1_5' }, cryptoKey, signature, data);\n\n\tif (!valid) {\n\t\tthrow new ProtocolError('JWT signature verification failed');\n\t}\n\n\treturn JSON.parse(new TextDecoder().decode(decodeBase64URL(encodedPayload))) as T;\n}\n\n/**\n * Generates a signed JWT token using the provided header, payload, and private key.\n *\n * @param {object} header - The JWT header.\n * @param {object} payload - The JWT payload.\n * @param {CryptoKey} [privateKey] - The private key to sign the JWT. If not provided, an unsigned token will be generated.\n * @returns {Promise<string>} A promise that resolves to the signed JWT token.\n */\nexport async function generateJwt(header: object, payload: object, privateKey?: CryptoKey): Promise<string> {\n\tconst encodedHeader = encodeBase64URL(new TextEncoder().encode(JSON.stringify(header)).buffer);\n\tconst encodedPayload = encodeBase64URL(new TextEncoder().encode(JSON.stringify(payload)).buffer);\n\tconst encodedToken = `${encodedHeader}.${encodedPayload}`;\n\n\tif (privateKey) {\n\t\tconst signature = await globalThis.crypto.subtle.sign(\n\t\t\t{\n\t\t\t\tname: 'ECDSA',\n\t\t\t\thash: { name: 'SHA-256' },\n\t\t\t},\n\t\t\tprivateKey,\n\t\t\tnew TextEncoder().encode(encodedToken),\n\t\t);\n\n\t\treturn `${encodedToken}.${encodeBase64URL(signature)}`;\n\t}\n\n\treturn `${encodedToken}.signature`;\n}\n\n/**\n * Verifies and validates an ID token's claims.\n *\n * @param {Object} options - The options for verifying the ID token\n * @param {string} options.idToken - The ID token to verify\n * @param {SDKOptions} options.options - The SDK options containing client ID, storage, and other options\n * @param {string} [options.expectedSub] - Optional expected subject (`sub`) claim to validate against the ID token\n * @param {string} [options.expectedNonce] - Optional expected nonce claim to validate against the ID token\n * @returns {Promise<IdTokenClaims>} The verified, validated claims.\n * @throws {ProtocolError} If the signature, `iss`, `aud`, `exp`, or `sub` fail validation.\n */\nexport async function verifyIdToken({\n\tidToken,\n\toptions,\n\tverifySignature = false,\n\texpectedSub,\n\texpectedNonce,\n}: {\n\tidToken: string;\n\toptions: SDKOptions;\n\tverifySignature?: boolean;\n\texpectedSub?: string;\n\texpectedNonce?: string;\n}): Promise<IdTokenClaims> {\n\tconst metadata = await getDiscoveryDocument(options);\n\tconst claims = verifySignature ? await verifyJwt<IdTokenClaims>({ token: idToken, options, jwksUri: metadata.jwks_uri }) : decodeJwt<IdTokenClaims>(idToken);\n\tconst now = timestamp();\n\n\tif (claims?.iss !== metadata.issuer) {\n\t\tthrow new ProtocolError('Invalid iss');\n\t}\n\tif (Array.isArray(claims?.aud) ? !claims.aud.includes(options.clientId) : claims?.aud !== options.clientId) {\n\t\tthrow new ProtocolError('Invalid aud');\n\t}\n\tif (!claims?.exp || claims.exp <= now) {\n\t\tthrow new ProtocolError('Token has expired');\n\t}\n\tif (!claims?.sub || (expectedSub && claims.sub !== expectedSub)) {\n\t\tthrow new ProtocolError('Invalid sub');\n\t}\n\tif (expectedNonce && claims?.nonce !== expectedNonce) {\n\t\tthrow new ProtocolError('Invalid nonce');\n\t}\n\n\treturn claims;\n}\n\n/**\n * Builds the authorization URL with the provided parameters and configuration.\n *\n * @param {Object} options - The options for building the login URL and starting the session\n * @param {ExtraRequestArgs} options.params - The parameters for the authorization request, including optional prompts and hints\n * @param {SDKOptions} options.options - The SDK options containing client ID, redirect URI, storage, and other options\n * @returns {Promise<URL>} A promise that resolves to the constructed authorization URL\n * @throws {Error} If fetching OIDC metadata fails or writing the PKCE state to storage fails.\n */\nexport async function buildAuthorizationUrl<URLHandlerParams extends ExtraRequestArgs = ExtraRequestArgs>({\n\turl,\n\tincludeOAuthParams = true,\n\tpersistState = true,\n\tparams,\n\toptions,\n}: {\n\turl?: string | null | URL;\n\tincludeOAuthParams?: boolean;\n\tpersistState?: boolean;\n\tparams: URLHandlerParams;\n\toptions: SDKOptions;\n}): Promise<URL> {\n\tconst stateData = await createState();\n\tstateData.metadata = {};\n\n\tif (!url) {\n\t\tconst metadata = await getDiscoveryDocument(options);\n\t\turl = new URL(metadata.authorization_endpoint);\n\t}\n\tif (typeof url === 'string') {\n\t\turl = new URL(url, globalThis.location.origin);\n\t}\n\n\tif (includeOAuthParams) {\n\t\tconst scopes = new Set(options.scopes ?? ['openid']);\n\n\t\turl.searchParams.set('client_id', options.clientId);\n\t\turl.searchParams.set('redirect_uri', options.redirectUri);\n\t\turl.searchParams.set('response_type', options.responseType ?? 'code');\n\t\turl.searchParams.set('response_mode', options.responseMode ?? 'query');\n\t\turl.searchParams.set('scope', Array.from(scopes).join(' '));\n\t\turl.searchParams.set('code_challenge_method', 'S256');\n\t\turl.searchParams.set('state', stateData.id);\n\t\turl.searchParams.set('code_challenge', stateData.codeChallenge);\n\n\t\tif (scopes.has('openid')) {\n\t\t\turl.searchParams.set('nonce', stateData.nonce);\n\t\t}\n\t}\n\n\tif (params.prompt) {\n\t\turl.searchParams.set('prompt', params.prompt);\n\t\tstateData.metadata.prompt = params.prompt;\n\t}\n\tif (params.display) {\n\t\turl.searchParams.set('display', params.display);\n\t\tstateData.metadata.display = params.display;\n\t}\n\tif (params.loginHint) {\n\t\turl.searchParams.set('login_hint', params.loginHint);\n\t\tstateData.metadata.loginHint = params.loginHint;\n\t}\n\tif (params.acrValues?.length) {\n\t\tconst acrValues = params.acrValues.filter(Boolean);\n\n\t\tif (acrValues.length) {\n\t\t\turl.searchParams.set('acr_values', acrValues.join(' '));\n\t\t\tstateData.metadata.acrValues = acrValues;\n\t\t}\n\t}\n\tif (params.uiLocales?.length) {\n\t\tconst uiLocales = params.uiLocales.filter(Boolean);\n\n\t\tif (uiLocales.length) {\n\t\t\turl.searchParams.set('ui_locales', uiLocales.join(' '));\n\t\t\tstateData.metadata.uiLocales = uiLocales;\n\t\t}\n\t}\n\tif (params.audiences?.length) {\n\t\tconst audiences = params.audiences.filter(Boolean);\n\n\t\tif (audiences.length) {\n\t\t\turl.searchParams.set('audience', audiences.join(' '));\n\t\t\tstateData.metadata.audiences = audiences;\n\t\t}\n\t}\n\n\tif (persistState) {\n\t\tawait options.stateStorage.set(`sty.${stateData.id}`, serializeState(stateData));\n\t}\n\n\treturn url;\n}\n\n/**\n * Builds the end session (logout) URL with optional parameters for ID token hint and post-logout redirect URI.\n *\n * @param {Object} options - The options for building the end session URL\n * @param {string | URL} options.url - The base URL for the end session endpoint\n * @param {string} options.idToken - The ID token to include as a hint for the end session request\n * @param {string} [options.postLogoutRedirectUri] - Optional URI to redirect to after logout\n * @returns {URL} A promise that resolves to the constructed end session URL\n * @throws {Error} If fetching metadata fails or the end session endpoint is not available\n */\nexport function buildEndSessionUrl({ url, idToken, postLogoutRedirectUri }: { url: string | URL; idToken: string; postLogoutRedirectUri?: string }): URL {\n\tconst endSessionUrl = new URL(url);\n\n\tendSessionUrl.searchParams.set('id_token_hint', idToken);\n\n\tif (postLogoutRedirectUri) {\n\t\tendSessionUrl.searchParams.set('post_logout_redirect_uri', postLogoutRedirectUri);\n\t}\n\n\treturn endSessionUrl;\n}\n\n/**\n * Exchanges an authorization code for tokens by sending a request to the token endpoint.\n * Validates the PKCE state and ID token claims, and returns the session data.\n *\n * @param {Object} options - The options for exchanging the authorization code\n * @param {string | URL} [options.url] - The token endpoint URL (optional, will be fetched from metadata if not provided)\n * @param {Record<string, string>} options.params - The parameters received from the authorization server, including the authorization code and state\n * @param {SDKOptions} options.options - The SDK options containing client ID, redirect URI, storage, and other options\n * @returns {Promise<SessionData>} A promise that resolves to the session data containing tokens and claims\n * @throws {OidcError} If the token endpoint returns an OIDC error response\n * @throws {ServerError} If the token endpoint request fails with a server error (HTTP 429 or 5xx)\n * @throws {NetworkError} If the token endpoint request fails due to network issues\n * @throws {ProtocolError} If the authorization code or state is invalid, or if the token endpoint returns an error\n * @throws {ProtocolError} If the authorization code or state is invalid, or if the token endpoint returns an error\n */\nexport async function exchangeCode({\n\turl,\n\tparams,\n\toptions,\n}: {\n\turl?: string | URL;\n\tparams: Record<string, string>;\n\toptions: SDKOptions;\n}): Promise<SessionData> {\n\tconst session = createSession(params);\n\n\tif (session.error) {\n\t\tthrow new OidcError(session.error, session.error_description, session.error_uri);\n\t}\n\tif (!session.code) {\n\t\tthrow new ProtocolError('Invalid or missing authorization code');\n\t}\n\n\tconst stateKey = `sty.${session.state}`;\n\tconst serializedState = await options.stateStorage.get(stateKey);\n\n\tif (!serializedState) {\n\t\tthrow new ProtocolError('Invalid or missing state');\n\t}\n\n\tlet state;\n\n\ttry {\n\t\tstate = parseState(serializedState);\n\t} catch {\n\t\tthrow new ProtocolError('Invalid or missing state');\n\t}\n\n\tawait options.stateStorage.delete(stateKey);\n\n\tconst metadata = await getDiscoveryDocument(options);\n\tconst tokenUrl = url ?? metadata.token_endpoint;\n\tconst response = await options.httpClient.sendTokenRequest<Record<string, string>>(tokenUrl, {\n\t\tgrant_type: 'authorization_code',\n\t\tclient_id: options.clientId,\n\t\tredirect_uri: options.redirectUri,\n\t\tcode_verifier: state.codeVerifier,\n\t\tcode: session.code,\n\t});\n\n\tif (!response.ok) {\n\t\tawait throwTokenEndpointError(response);\n\t}\n\n\tlet data: Record<string, string>;\n\n\ttry {\n\t\tdata = await response.json();\n\t} catch {\n\t\tthrow new ProtocolError('Non-JSON response from token endpoint');\n\t}\n\n\tconst updatedSession: SessionData = { ...params, ...createSession(data) };\n\n\tif (updatedSession.error) {\n\t\tthrow new OidcError(updatedSession.error, updatedSession.error_description, updatedSession.error_uri);\n\t}\n\n\tif (updatedSession.id_token) {\n\t\tupdatedSession.claims = await verifyIdToken({ idToken: updatedSession.id_token, expectedNonce: state.nonce, options });\n\t}\n\n\treturn updatedSession;\n}\n\n/**\n * Refreshes the access token using the stored refresh token and persists the updated session.\n *\n * @param {Object} options - The options for refreshing the access token\n * @param {string} options.url - The token endpoint URL\n * @param {string} options.refreshToken - The refresh token to use for refreshing the access token\n * @param {SDKOptions} options.options - The SDK options containing client ID, storage, and other options\n * @param {string} [options.grantType='refresh_token'] - The grant type to use for the token refresh request (default is 'refresh_token')\n * @param {string} [options.clientId] - Optional client ID to override the default client ID in the SDK options\n * @param {string} [options.audience] - Optional audience to include in the token refresh request\n * @param {string} [options.scope] - Optional scope to include in the token refresh request\n * @returns {Promise<SessionData>} A promise that resolves to the updated session data with refreshed tokens\n * @throws {ServerError} If the token refresh request fails with a server error (HTTP 429 or 5xx)\n * @throws {NetworkError} If the token refresh request fails due to network issues\n * @throws {OidcError} If the token refresh request returns an OIDC error response\n * @throws {ProtocolError} If the token refresh request returns an error or the ID token claims are invalid\n */\nexport async function refreshToken({\n\turl,\n\trefreshToken,\n\toptions,\n\tgrantType = 'refresh_token',\n\tclientId,\n\taudience,\n\tscope,\n\texpectedSub,\n}: {\n\turl?: string | URL;\n\trefreshToken: string;\n\toptions: SDKOptions;\n\tgrantType?: string;\n\tclientId?: string;\n\taudience?: string;\n\tscope?: string;\n\texpectedSub?: string;\n}): Promise<SessionData> {\n\tconst params: Record<string, string> = {\n\t\tgrant_type: grantType,\n\t\tclient_id: clientId ?? options.clientId,\n\t\trefresh_token: refreshToken,\n\t};\n\n\tif (audience) {\n\t\tparams.audience = audience;\n\t}\n\n\tif (scope) {\n\t\tparams.scope = scope;\n\t}\n\n\tconst metadata = await getDiscoveryDocument(options);\n\tconst refreshUrl = url ?? metadata.token_endpoint;\n\tconst response = await options.httpClient.sendTokenRequest<Record<string, string>>(refreshUrl, params);\n\n\tif (!response.ok) {\n\t\tawait throwTokenEndpointError(response);\n\t}\n\n\tlet data: Record<string, string>;\n\n\ttry {\n\t\tdata = await response.json();\n\t} catch {\n\t\tthrow new ProtocolError('Non-JSON response from token endpoint');\n\t}\n\n\tconst updatedSession: SessionData = createSession(data);\n\n\tif (updatedSession.error) {\n\t\tthrow new OidcError(updatedSession.error, updatedSession.error_description, updatedSession.error_uri);\n\t}\n\n\tif (updatedSession.id_token) {\n\t\tupdatedSession.claims = await verifyIdToken({ idToken: updatedSession.id_token, expectedSub, options });\n\t}\n\n\treturn updatedSession;\n}\n\n/**\n * Revokes the best available token (refresh token preferred, then access token) and removes the session from storage.\n *\n * @param {Object} options - The options for revoking the token\n * @param {string | URL} options.url - The revocation endpoint URL\n * @param {string} options.tokenTypeHint - The type of token to revoke ('refresh_token' or 'access_token')\n * @param {string} options.token - The token to revoke\n * @param {SDKOptions} options.options - The SDK options containing client ID, storage, and other options\n * @param {string} [options.clientId] - Optional client ID to override the default client ID in the SDK options\n * @returns {Promise<void>} A promise that resolves when the token is revoked and the session is cleared from storage\n * @throws {ServerError} If the token revocation request fails with a server error (HTTP 429 or 5xx)\n * @throws {ProtocolError} If the token revocation request returns an error or the ID token claims are invalid\n */\nexport async function revokeToken({\n\turl,\n\ttokenTypeHint,\n\ttoken,\n\toptions,\n\tclientId,\n}: {\n\turl?: string | URL;\n\ttokenTypeHint: string;\n\ttoken: string;\n\toptions: SDKOptions;\n\tclientId?: string;\n}): Promise<void> {\n\tconst metadata = await getDiscoveryDocument(options);\n\tconst revokeUrl = url ?? metadata.revocation_endpoint;\n\n\tif (!revokeUrl) {\n\t\toptions.logging?.debug('Revocation skipped: no revocation_endpoint available');\n\t\treturn;\n\t}\n\n\tconst response = await options.httpClient.sendTokenRequest<Record<string, string>>(revokeUrl, {\n\t\tclient_id: clientId ?? options.clientId,\n\t\ttoken_type_hint: tokenTypeHint,\n\t\ttoken,\n\t});\n\n\tif (response && !response.ok) {\n\t\tawait throwTokenEndpointError(response);\n\t}\n}\n\n/**\n * Fetches the entry flow from the specified URL with the provided parameters and SDK options.\n *\n * @param {Object} options\n * @param {string | URL} options.url - The URL to request the entry flow from\n * @param {URLSearchParams} options.params - The parameters to include in the entry request\n * @param {SDKOptions} options.options - The SDK options containing client ID, redirect URI, storage, and other options\n * @param {string} [options.clientId] - Optional client ID to override the default client ID in the SDK options\n * @param {string} [options.redirectUri] - Optional redirect URI to override the default redirect URI in the SDK options\n * @param {string} [options.sdkMode='web'] - Optional SDK mode to include in the entry request (default is 'web')\n * @returns {Promise<EntryResponse>} A promise resolving to the entry result.\n * @throws {OidcError} If the entry request returns an OIDC error response.\n * @throws {ServerError} If the entry request fails with a server error (HTTP 429 or 5xx).\n * @throws {ProtocolError} If the entry request fails with a protocol error or missing required fields.\n */\nexport async function fetchFlowEntry({\n\turl,\n\tparams,\n\toptions,\n\tclientId,\n\tredirectUri,\n\tsdkMode = 'web',\n}: {\n\turl: string | URL;\n\tparams: URLSearchParams;\n\toptions: SDKOptions;\n\tclientId?: string;\n\tredirectUri?: string;\n\tsdkMode?: string;\n}): Promise<EntryResponse> {\n\tparams.set('sdk', sdkMode);\n\tparams.set('client_id', clientId ?? options.clientId);\n\tparams.set('redirect_uri', redirectUri ?? options.redirectUri);\n\n\tconst requestUrl = new URL(url);\n\trequestUrl.search = params.toString();\n\n\tconst response = await options.httpClient.request<string | Record<string, string>>(requestUrl);\n\n\tif (!response.ok) {\n\t\tif (response.status === 400) {\n\t\t\tconst data = await response.json();\n\n\t\t\tif (data && typeof data === 'object') {\n\t\t\t\tif (data.error) {\n\t\t\t\t\tthrow new OidcError(data.error, data.error_description, data.error_uri);\n\t\t\t\t} else if (data.errorKey) {\n\t\t\t\t\tthrow new ProtocolError(data.errorKey);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthrow new ProtocolError('Entry request failed');\n\t\t}\n\n\t\tthrowHttpError(response.status, 'Entry request failed');\n\t}\n\n\tlet uri: URL;\n\tlet searchParams: Record<string, string>;\n\n\ttry {\n\t\turi = new URL(await response.text());\n\t\tsearchParams = Object.fromEntries(uri.searchParams.entries());\n\t} catch {\n\t\turi = new URL(response.url);\n\t\tsearchParams = Object.fromEntries(uri.searchParams.entries());\n\t}\n\n\tconst shortAppId = searchParams.short_app_id;\n\tconst sessionId = searchParams.session_id;\n\tconst language = searchParams.language || globalThis.navigator?.language || 'en-US';\n\n\tif (!sessionId) {\n\t\tthrow new ProtocolError('\"session_id\" is missing from the response');\n\t}\n\n\treturn { session_id: sessionId, short_app_id: shortAppId, language };\n}\n\n/**\n * Finalizes the login session using the provided url.\n *\n * @param {Object} options - The options for finalizing the session\n * @param {string | URL} options.url - The URL to finalize the session.\n * @param {string} options.sessionId - The session ID to finalize the session with.\n * @param {string} options.language - The language to use for the session.\n * @param {SDKOptions} options.options - The SDK options containing client ID, redirect URI, storage, and other options.\n * @returns {Promise<URL>} A promise that resolves to the redirect URL after finalizing the session.\n * @throws {ServerError} If the request to finalize the session fails with a server error (HTTP 429 or 5xx).\n * @throws {ProtocolError} If the response from the server is invalid or does not contain a valid redirect URI.\n */\nexport async function finalizeLoginSession({\n\turl,\n\tsessionId,\n\tlanguage,\n\toptions,\n}: {\n\turl: string | URL;\n\tsessionId: string;\n\tlanguage: string;\n\toptions: SDKOptions;\n}): Promise<URL> {\n\tconst response = await options.httpClient.request(url, {\n\t\tmethod: 'GET',\n\t\tcredentials: 'include',\n\t\theaders: {\n\t\t\tAuthorization: `Bearer ${sessionId}`,\n\t\t\t'Accept-language': language,\n\t\t},\n\t});\n\n\tif (!response.ok) {\n\t\tthrowHttpError(response.status, 'Failed to finalize login session');\n\t}\n\n\tlet redirectUri: URL;\n\n\ttry {\n\t\tredirectUri = new URL(await response.text());\n\t} catch {\n\t\tthrow new ProtocolError('Invalid redirect URI');\n\t}\n\n\tif (!redirectUri.toString().startsWith(options.redirectUri)) {\n\t\tthrow new ProtocolError('Invalid redirect URI');\n\t}\n\n\treturn redirectUri;\n}\n\n/**\n * Submits a login form to the authentication server.\n *\n * @param {Object} options - The options for submitting the form.\n * @param {string} [options.formId] - The ID of the form to submit. If not provided, the init endpoint is used.\n * @param {Record<string, unknown>} [options.body] - The form data to include in the request body.\n * @param {string} options.sessionId - The session ID for the current authentication session.\n * @param {string} options.language - The language preference sent in the `Accept-language` header.\n * @param {SDKOptions} options.options - The SDK options.\n * @returns {Promise<NativeFlowState>} A promise that resolves to the current login flow state.\n * @throws {ServerError} If the server returns a non-recoverable HTTP error.\n * @throws {FallbackError} If the server indicates the flow should fall back to the hosted UI.\n * @throws {SessionExpiredError} If the session has expired (HTTP 403).\n */\nexport async function submitLoginForm({\n\tformId,\n\tbody,\n\tsessionId,\n\tlanguage,\n\toptions,\n}: {\n\tformId?: string;\n\tbody?: Record<string, unknown>;\n\tsessionId: string;\n\tlanguage: string;\n\toptions: SDKOptions;\n}): Promise<NativeFlowState> {\n\tconst response = await options.httpClient.request<NativeFlowState>(new URL(`/flow/api/v1/${formId ? `form/${formId}` : 'init'}`, options.issuer), {\n\t\tmethod: 'POST',\n\t\tcredentials: 'include',\n\t\tbody: JSON.stringify(body),\n\t\theaders: {\n\t\t\tAuthorization: `Bearer ${sessionId}`,\n\t\t\t'Content-Type': 'application/json',\n\t\t\t'Accept-language': language,\n\t\t},\n\t});\n\tlet data: NativeFlowState = {};\n\n\ttry {\n\t\tdata = await response.json();\n\t} catch {}\n\n\tif (!response.ok) {\n\t\tif (response.status === 403) {\n\t\t\tthrow new SessionExpiredError();\n\t\t}\n\n\t\tif (response.status >= 400 && response.status < 500 && data?.hostedUrl && !data.messages) {\n\t\t\tthrow new FallbackError(new URL(data.hostedUrl), `Received HTTP ${response.status} without messages`);\n\t\t}\n\n\t\tthrowHttpError(response.status, 'Failed to submit login form');\n\t}\n\n\tif (data.hostedUrl && !data.finalizeUrl && !data.forms && !data.messages) {\n\t\tthrow new FallbackError(new URL(data.hostedUrl), 'No forms or messages in response');\n\t}\n\n\treturn data;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=require("../utils/errors.cjs"),t=require("./oidc.cjs"),n=require("../utils/crypto.cjs");var r=`strivacity-session-v1`,i=3900;function a(){return globalThis.sty??={},globalThis.sty.storage??=new Map,{async get(e){return Promise.resolve(globalThis.sty.storage?.get(e)??null)},async set(e,t){return globalThis.sty.storage?.set(e,t),Promise.resolve()},async delete(e){return globalThis.sty.storage?.delete(e),Promise.resolve()}}}function o(){return globalThis.sty??={},globalThis.sty.storage=new Map,{get:e=>Promise.resolve(globalThis.sty.storage.get(e)??null),set:(e,t)=>(globalThis.sty.storage.set(e,t),Promise.resolve()),delete:e=>(globalThis.sty.storage.delete(e),Promise.resolve()),deleteByLogoutToken:e=>{for(let[t,n]of globalThis.sty.storage){let r=JSON.parse(n)?.claims;(e.sid&&r?.sid===e.sid||e.sub&&r?.sub===e.sub)&&globalThis.sty.storage.delete(t)}return Promise.resolve()}}}function s(e,t,n){let r={httpOnly:!0,secure:!0,sameSite:`lax`,path:`/`,...n?.defaultCookieOptions};return e.getSessionId||=async(t,n)=>n?h((await e.toRequest(n)).headers.get(`cookie`))[t]:null,{async get(n,r){let i=await e.getSessionId(n,r);return i?await t.get(i):null},async set(i,a,o){let s=await e.getSessionId(i,o);s||(s=n?.uuidGenerator?.()??globalThis.crypto.randomUUID(),_(o,g(i,s,r))),await t.set(s,a)},async delete(n,i){let a=await e.getSessionId(n,i);a&&await t.delete(a),_(i,g(n,``,{...r,expires:new Date(0)}))},async deleteByLogoutToken(e){await t.deleteByLogoutToken?.(e)}}}function c(e,t,a){let o={httpOnly:!0,secure:!0,sameSite:`lax`,path:`/`,...a?.defaultCookieOptions};async function s(e,n){return e?h((await t.toRequest(e)).headers.get(`cookie`))[n]:void 0}let c={async get(t,i){let a=await s(i,t);if(a)return await n.decryptString(a,e,r);let o=[];for(let e=0;;e++){let n=await s(i,`${t}.${e}`);if(!n)break;o.push(n)}return o.length===0?null:await n.decryptString(o.join(``),e,r)},async set(t,a,s){await c.delete(t,s);let l=await n.encryptString(a,e,r);if(l.length<=3900)_(s,g(t,l,o));else for(let e=0;e*i<l.length;e++)_(s,g(`${t}.${e}`,l.slice(e*i,(e+1)*i),o))},async delete(e,t){let n={...o,expires:new Date(0)};_(t,g(e,``,n));for(let r=0;await s(t,`${e}.${r}`);r++)_(t,g(`${e}.${r}`,``,n))}};return c}var l=new Set([`transfer-encoding`,`connection`,`keep-alive`,`content-encoding`]),u=`sty.returnTo`,d=`http://schemas.openid.net/event/backchannel-logout`,f=2592e3,p=new WeakMap;function m(n,r){if(r.postLoginRedirectUri??=new URL(r.redirectUri).origin,r.postLogoutRedirectUri??=new URL(r.redirectUri).origin,r.cookieMaxAge??=f,!r.storage){if(!r.secret)throw new e.ConfigurationError(`Missing SDK option: secret`);r.storage=c(r.secret,n,{defaultCookieOptions:{maxAge:r.cookieMaxAge}})}return r.stateStorage??=a(),r.urlHandler??=async()=>Promise.resolve(void 0),r.authUrlPrefix??=`/auth`,r.loginUri??=`/login`,r.serverSessionUri===void 0&&(r.serverSessionUri??=`${r.authUrlPrefix}/login`),t.m(r)}function h(e){let t={};if(!e)return t;for(let n of e.split(`;`)){let e=n.indexOf(`=`);if(e===-1)continue;let r=n.slice(0,e).trim(),i=n.slice(e+1).trim();if(r)try{t[r]=decodeURIComponent(i)}catch{t[r]=i}}return t}function g(e,t,n={}){let r=[`${e}=${encodeURIComponent(t)}`];return typeof n.maxAge==`number`&&r.push(`Max-Age=${Math.floor(n.maxAge)}`),n.expires&&r.push(`Expires=${n.expires.toUTCString()}`),r.push(`Path=${n.path??`/`}`),n.domain&&r.push(`Domain=${n.domain}`),n.sameSite&&r.push(`SameSite=${n.sameSite.charAt(0).toUpperCase()}${n.sameSite.slice(1)}`),n.secure&&r.push(`Secure`),n.httpOnly&&r.push(`HttpOnly`),r.join(`; `)}function _(t,n){if(typeof t!=`object`||!t)throw new e.InternalError(`Server adapter events must be objects to track outgoing cookies`);let r=p.get(t)??[];r.push(n),p.set(t,r)}function v(t,n){if(typeof t!=`object`||!t)throw new e.InternalError(`Server adapter events must be objects to track outgoing cookies`);let r=p.get(t);if(r?.length){for(let e of r)n.headers.append(`set-cookie`,e);p.delete(t)}return n}function y(e){let t=new Headers;for(let[n,r]of e.headers.entries())n.toLowerCase()!==`set-cookie`&&(l.has(n.toLowerCase())||t.set(n,r));let n=e.headers.get(`set-cookie`)?.split(`,`).map(e=>e.trim());return n?.length&&t.set(`set-cookie`,n.join(`, `)),new Response(e.body,{status:e.status,statusText:e.statusText,headers:t})}function b(e,t){let n;if(!e)return null;try{n=new URL(e.startsWith(`/`)?e.slice(1):e,t&&!t.endsWith(`/`)?`${t}/`:t)}catch{return null}return n.origin===new URL(t).origin?n.toString():null}Object.defineProperty(exports,"_",{enumerable:!0,get:function(){return s}}),Object.defineProperty(exports,"a",{enumerable:!0,get:function(){return v}}),Object.defineProperty(exports,"c",{enumerable:!0,get:function(){return y}}),Object.defineProperty(exports,"d",{enumerable:!0,get:function(){return b}}),Object.defineProperty(exports,"f",{enumerable:!0,get:function(){return i}}),Object.defineProperty(exports,"g",{enumerable:!0,get:function(){return a}}),Object.defineProperty(exports,"h",{enumerable:!0,get:function(){return o}}),Object.defineProperty(exports,"i",{enumerable:!0,get:function(){return u}}),Object.defineProperty(exports,"l",{enumerable:!0,get:function(){return _}}),Object.defineProperty(exports,"m",{enumerable:!0,get:function(){return c}}),Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return f}}),Object.defineProperty(exports,"o",{enumerable:!0,get:function(){return m}}),Object.defineProperty(exports,"p",{enumerable:!0,get:function(){return r}}),Object.defineProperty(exports,"r",{enumerable:!0,get:function(){return l}}),Object.defineProperty(exports,"s",{enumerable:!0,get:function(){return h}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return d}}),Object.defineProperty(exports,"u",{enumerable:!0,get:function(){return g}});
|
|
2
|
+
//# sourceMappingURL=server.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.cjs","names":[],"sources":["../../src/storages/server.ts","../../src/utils/server.ts"],"sourcesContent":["import type { SDKStorage } from '../types/common';\nimport type { EncryptedCookieStorageOptions, ServerAdapter, ServerCookieOptions, ServerStorage, SessionIdCookieStorageOptions } from '../types/server';\nimport { encryptString, decryptString } from '../utils/crypto';\nimport { parseCookieHeader, pushSetCookie, serializeCookie } from '../utils/server';\n\nexport const COOKIE_CONTEXT = 'strivacity-session-v1';\nexport const COOKIE_CHUNK_SIZE = 3900;\n\n/**\n * Creates a simple in-memory state storage implementation, shared across all server adapters.\n *\n * @returns {SDKStorage} An object implementing the SDKStorage interface.\n */\nexport function createServerStateStorage(): SDKStorage {\n\tglobalThis.sty ??= {} as typeof globalThis.sty;\n\tglobalThis.sty.storage ??= new Map<string, string>();\n\n\treturn {\n\t\tasync get(key) {\n\t\t\treturn Promise.resolve(globalThis.sty.storage?.get(key) ?? null);\n\t\t},\n\t\tasync set(key, value) {\n\t\t\tglobalThis.sty.storage?.set(key, value);\n\n\t\t\treturn Promise.resolve();\n\t\t},\n\t\tasync delete(key) {\n\t\t\tglobalThis.sty.storage?.delete(key);\n\n\t\t\treturn Promise.resolve();\n\t\t},\n\t};\n}\n\n/**\n * In-memory global storage adapter for session data.\n * Not recommended for production use, as session data will be lost on server restart.\n *\n * @returns {ServerStorage} An object implementing the ServerStorage interface.\n */\nexport function createServerMemoryStorage(): ServerStorage {\n\tglobalThis.sty ??= {} as typeof globalThis.sty;\n\tglobalThis.sty.storage = new Map<string, string>();\n\n\treturn {\n\t\tget: (key) => {\n\t\t\treturn Promise.resolve(globalThis.sty.storage!.get(key) ?? null);\n\t\t},\n\t\tset: (key, value) => {\n\t\t\tglobalThis.sty.storage!.set(key, value);\n\n\t\t\treturn Promise.resolve();\n\t\t},\n\t\tdelete: (key) => {\n\t\t\tglobalThis.sty.storage!.delete(key);\n\n\t\t\treturn Promise.resolve();\n\t\t},\n\t\tdeleteByLogoutToken: (logoutToken) => {\n\t\t\tfor (const [mapKey, raw] of globalThis.sty.storage!) {\n\t\t\t\tconst claims = JSON.parse(raw)?.claims;\n\n\t\t\t\tif ((logoutToken.sid && claims?.sid === logoutToken.sid) || (logoutToken.sub && claims?.sub === logoutToken.sub)) {\n\t\t\t\t\tglobalThis.sty.storage!.delete(mapKey);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn Promise.resolve();\n\t\t},\n\t};\n}\n\n/**\n * Creates a session storage that puts a session-id value cookie on the client and keeping the actual session data in the given `storage`.\n *\n * @param {ServerAdapter<TEvent>} adapter - The framework adapter used to read the incoming request.\n * @param {ServerStorage<TEvent>} storage - The storage used to persist session data, keyed by a randomly generated session id.\n * @param {SessionIdCookieStorageOptions} [options] - Options for the session ID cookie, including default cookie attributes and a UUID generator function.\n * @param {Partial<ServerCookieOptions>} [options.defaultCookieOptions] - Default cookie attributes for the session ID cookie.\n * @param {() => string} [options.uuidGenerator] - Function to generate a new UUID for the session ID. Defaults to `() => crypto.randomUUID()`.\n * @returns {ServerStorage<TEvent>} An object implementing the `ServerStorage` interface for managing sessions indexed by a session-id cookie.\n */\nexport function createSessionIdCookieStorage<TEvent = unknown>(\n\tadapter: ServerAdapter<TEvent>,\n\tstorage: ServerStorage,\n\toptions?: SessionIdCookieStorageOptions,\n): ServerStorage<TEvent> {\n\tconst defaultCookieOptions: ServerCookieOptions = {\n\t\thttpOnly: true,\n\t\tsecure: true,\n\t\tsameSite: 'lax',\n\t\tpath: '/',\n\t\t...options?.defaultCookieOptions,\n\t};\n\n\tif (!adapter.getSessionId) {\n\t\tadapter.getSessionId = async (key: string, event?: TEvent) => {\n\t\t\tif (!event) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst request = await adapter.toRequest(event);\n\t\t\tconst cookies = parseCookieHeader(request.headers.get('cookie'));\n\n\t\t\treturn cookies[key];\n\t\t};\n\t}\n\n\treturn {\n\t\tasync get(key, event) {\n\t\t\tconst id = await adapter.getSessionId!(key, event);\n\n\t\t\treturn id ? await storage.get(id) : null;\n\t\t},\n\t\tasync set(key, value, event) {\n\t\t\tlet id = await adapter.getSessionId!(key, event);\n\n\t\t\tif (!id) {\n\t\t\t\tid = options?.uuidGenerator?.() ?? globalThis.crypto.randomUUID();\n\t\t\t\tpushSetCookie(event, serializeCookie(key, id, defaultCookieOptions));\n\t\t\t}\n\n\t\t\tawait storage.set(id, value);\n\t\t},\n\t\tasync delete(key, event) {\n\t\t\tconst id = await adapter.getSessionId!(key, event);\n\n\t\t\tif (id) {\n\t\t\t\tawait storage.delete(id);\n\t\t\t}\n\n\t\t\tpushSetCookie(event, serializeCookie(key, '', { ...defaultCookieOptions, expires: new Date(0) }));\n\t\t},\n\t\tasync deleteByLogoutToken(token) {\n\t\t\tawait storage.deleteByLogoutToken?.(token);\n\t\t},\n\t};\n}\n\n/**\n * Creates an encrypted session storage backed by cookies.\n * Built entirely on top of `adapter.toRequest`'s `Request` (reading the `cookie` header) and the outgoing cookie jar (writing `set-cookie` headers).\n *\n * @param {string} secret - The secret key used for encryption and decryption.\n * @param {ServerAdapter<TEvent>} adapter - The framework adapter used to read the incoming request.\n * @param {EncryptedCookieStorageOptions} [options] - Cookie attributes (maxAge, sameSite, etc.). `path` defaults to `'/'`.\n * @param {Partial<ServerCookieOptions>} [options.defaultCookieOptions] - Default cookie attributes for the session ID cookie.\n * @returns {ServerStorage<TEvent>} An object implementing the `ServerStorage` interface for managing encrypted session cookies.\n */\nexport function createEncryptedCookieStorage<TEvent = unknown>(\n\tsecret: string,\n\tadapter: ServerAdapter<TEvent>,\n\toptions?: EncryptedCookieStorageOptions,\n): ServerStorage<TEvent> {\n\tconst defaultCookieOptions: ServerCookieOptions = {\n\t\thttpOnly: true,\n\t\tsecure: true,\n\t\tsameSite: 'lax',\n\t\tpath: '/',\n\t\t...options?.defaultCookieOptions,\n\t};\n\n\tasync function getIncomingCookie(event: TEvent | undefined, name: string): Promise<string | undefined> {\n\t\tif (!event) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst request = await adapter.toRequest(event);\n\t\tconst cookies = parseCookieHeader(request.headers.get('cookie'));\n\n\t\treturn cookies[name];\n\t}\n\n\tconst storage: ServerStorage<TEvent> = {\n\t\tasync get(key, event) {\n\t\t\tconst cookie = await getIncomingCookie(event, key);\n\n\t\t\tif (cookie) {\n\t\t\t\t// NOTE: If the cookie is present, we can decrypt it directly without checking for chunks.\n\t\t\t\treturn await decryptString(cookie, secret, COOKIE_CONTEXT);\n\t\t\t}\n\n\t\t\t// NOTE: If the cookie is not present, we check for chunked cookies (e.g., `key.0`, `key.1`, etc.) and concatenate them before decryption.\n\t\t\tconst cookieChunks: Array<string> = [];\n\n\t\t\tfor (let i = 0; ; i++) {\n\t\t\t\tconst chunk = await getIncomingCookie(event, `${key}.${i}`);\n\n\t\t\t\tif (!chunk) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcookieChunks.push(chunk);\n\t\t\t}\n\n\t\t\tif (cookieChunks.length === 0) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\treturn await decryptString(cookieChunks.join(''), secret, COOKIE_CONTEXT);\n\t\t},\n\n\t\tasync set(key, value, event) {\n\t\t\t// NOTE: Delete existing cookie(s) first to avoid leaving old chunks behind\n\t\t\tawait storage.delete(key, event);\n\n\t\t\tconst encrypted = await encryptString(value, secret, COOKIE_CONTEXT);\n\n\t\t\tif (encrypted.length <= COOKIE_CHUNK_SIZE) {\n\t\t\t\tpushSetCookie(event, serializeCookie(key, encrypted, defaultCookieOptions));\n\t\t\t} else {\n\t\t\t\tfor (let i = 0; i * COOKIE_CHUNK_SIZE < encrypted.length; i++) {\n\t\t\t\t\tpushSetCookie(event, serializeCookie(`${key}.${i}`, encrypted.slice(i * COOKIE_CHUNK_SIZE, (i + 1) * COOKIE_CHUNK_SIZE), defaultCookieOptions));\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\tasync delete(key, event) {\n\t\t\tconst expiredOptions = { ...defaultCookieOptions, expires: new Date(0) };\n\n\t\t\tpushSetCookie(event, serializeCookie(key, '', expiredOptions));\n\n\t\t\tfor (let i = 0; await getIncomingCookie(event, `${key}.${i}`); i++) {\n\t\t\t\tpushSetCookie(event, serializeCookie(`${key}.${i}`, '', expiredOptions));\n\t\t\t}\n\t\t},\n\t};\n\n\treturn storage;\n}\n","import type { HttpClientResponse, SDKStorage, ServerCookieOptions, ServerAdapter, ServerSDKOptions, ServerStorage } from '../types';\nimport { getSDKOptions } from './oidc';\nimport { createServerStateStorage, createEncryptedCookieStorage } from '../storages/server';\nimport { ConfigurationError, InternalError } from './errors';\n\n/**\n * Disallowed headers that should not be proxied from the SDK to the client, as they may interfere with the response handling.\n */\nexport const DISALLOWED_PROXY_HEADERS = new Set(['transfer-encoding', 'connection', 'keep-alive', 'content-encoding']);\n\n/**\n * Returns with the returnTo cookie name used for storing the returnTo URL in the server SDK.\n */\nexport const RETURN_TO_COOKIE = 'sty.returnTo';\n\n/**\n * Backchannel logout event name used for identifying backchannel logout requests in the server SDK.\n */\nexport const BACKCHANNEL_LOGOUT_EVENT = 'http://schemas.openid.net/event/backchannel-logout';\n\n/**\n * Default cookie max age in seconds (30 days).\n */\nexport const DEFAULT_COOKIE_MAX_AGE = 30 * 24 * 60 * 60;\n\n/**\n * A WeakMap to store cookies for each request event, allowing for proper cookie management in server-side environments.\n */\nconst cookieJars = new WeakMap<object, Array<string>>();\n\n/**\n * Returns with the server SDK options merged with the provided options.\n *\n * @param {SDKInitConfig} options - The SDK initialization configuration.\n * @template InitOptions - The type of the SDK initialization configuration.\n * @template Options - The type of the SDK options.\n * @returns {Options} The merged SDK options.\n */\nexport function getServerSDKOptions<\n\tTEvent = unknown,\n\tStorage extends ServerStorage<TEvent> = ServerStorage<TEvent>,\n\tStateStorage extends SDKStorage = SDKStorage,\n\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n>(adapter: ServerAdapter<TEvent>, options: any): ServerSDKOptions<TEvent, Storage, StateStorage> {\n\toptions.postLoginRedirectUri ??= new URL(options.redirectUri).origin;\n\toptions.postLogoutRedirectUri ??= new URL(options.redirectUri).origin;\n\toptions.cookieMaxAge ??= DEFAULT_COOKIE_MAX_AGE;\n\n\tif (!options.storage) {\n\t\tif (!options.secret) {\n\t\t\tthrow new ConfigurationError('Missing SDK option: secret');\n\t\t}\n\n\t\toptions.storage = createEncryptedCookieStorage<TEvent>(options.secret, adapter, { defaultCookieOptions: { maxAge: options.cookieMaxAge } });\n\t}\n\n\toptions.stateStorage ??= createServerStateStorage();\n\toptions.urlHandler ??= async () => Promise.resolve(undefined);\n\toptions.authUrlPrefix ??= '/auth';\n\toptions.loginUri ??= '/login';\n\n\tif (typeof options.serverSessionUri === 'undefined') {\n\t\toptions.serverSessionUri ??= `${options.authUrlPrefix}/login`;\n\t}\n\n\treturn getSDKOptions(options);\n}\n\n/**\n * Parses a `Cookie` request header into a plain name/value map.\n *\n * @param {string | null | undefined} header - The raw `Cookie` header value.\n * @returns {Record<string, string>} The parsed cookies.\n */\nexport function parseCookieHeader(header: string | null | undefined): Record<string, string> {\n\tconst cookies: Record<string, string> = {};\n\n\tif (!header) {\n\t\treturn cookies;\n\t}\n\n\tfor (const part of header.split(';')) {\n\t\tconst index = part.indexOf('=');\n\n\t\tif (index === -1) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst name = part.slice(0, index).trim();\n\t\tconst value = part.slice(index + 1).trim();\n\n\t\tif (name) {\n\t\t\ttry {\n\t\t\t\tcookies[name] = decodeURIComponent(value);\n\t\t\t} catch {\n\t\t\t\tcookies[name] = value;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn cookies;\n}\n\n/**\n * Serializes a name/value pair into a `Set-Cookie` header value.\n *\n * @param {string} name - The cookie name.\n * @param {string} value - The cookie value.\n * @param {ServerCookieOptions} [options] - The cookie attributes.\n * @returns {string} The serialized `Set-Cookie` header value.\n */\nexport function serializeCookie(name: string, value: string, options: ServerCookieOptions = {}): string {\n\tconst segments = [`${name}=${encodeURIComponent(value)}`];\n\n\tif (typeof options.maxAge === 'number') {\n\t\tsegments.push(`Max-Age=${Math.floor(options.maxAge)}`);\n\t}\n\tif (options.expires) {\n\t\tsegments.push(`Expires=${options.expires.toUTCString()}`);\n\t}\n\n\tsegments.push(`Path=${options.path ?? '/'}`);\n\n\tif (options.domain) {\n\t\tsegments.push(`Domain=${options.domain}`);\n\t}\n\tif (options.sameSite) {\n\t\tsegments.push(`SameSite=${options.sameSite.charAt(0).toUpperCase()}${options.sameSite.slice(1)}`);\n\t}\n\tif (options.secure) {\n\t\tsegments.push('Secure');\n\t}\n\tif (options.httpOnly) {\n\t\tsegments.push('HttpOnly');\n\t}\n\n\treturn segments.join('; ');\n}\n\n/**\n * Pushes a `Set-Cookie` header value into the cookie jar for the given event.\n *\n * @param {unknown} event - The framework-native request event.\n * @param {string} header - The `Set-Cookie` header value to push.\n */\nexport function pushSetCookie(event: unknown, header: string): void {\n\tif (event === null || typeof event !== 'object') {\n\t\tthrow new InternalError('Server adapter events must be objects to track outgoing cookies');\n\t}\n\n\tconst jar = cookieJars.get(event) ?? [];\n\tjar.push(header);\n\tcookieJars.set(event, jar);\n}\n\n/**\n * Flushes the accumulated `Set-Cookie` headers from the cookie jar into the provided `Response`.\n *\n * @param {unknown} event - The framework-native request event.\n * @param {Response} response - The `Response` object to append the `Set-Cookie` headers to.\n * @returns {Response} The modified `Response` with the appended `Set-Cookie` headers.\n */\nexport function flushSetCookies(event: unknown, response: Response): Response {\n\tif (event === null || typeof event !== 'object') {\n\t\tthrow new InternalError('Server adapter events must be objects to track outgoing cookies');\n\t}\n\n\tconst jar = cookieJars.get(event);\n\n\tif (jar?.length) {\n\t\tfor (const header of jar) {\n\t\t\tresponse.headers.append('set-cookie', header);\n\t\t}\n\n\t\tcookieJars.delete(event);\n\t}\n\n\treturn response;\n}\n\n/**\n * Proxies an `HttpClientResponse` to a Web `Response`, preserving headers and status code.\n *\n * @param {HttpClientResponse<T>} response - The `HttpClientResponse` to proxy.\n * @returns {Response} A `Response` object representing the proxied response.\n */\nexport function proxyResponse<T = unknown>(response: HttpClientResponse<T>): Response {\n\tconst proxyHeaders = new Headers();\n\n\tfor (const [key, value] of response.headers.entries()) {\n\t\tif (key.toLowerCase() === 'set-cookie') {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (!DISALLOWED_PROXY_HEADERS.has(key.toLowerCase())) {\n\t\t\tproxyHeaders.set(key, value);\n\t\t}\n\t}\n\n\tconst proxyCookies = response.headers\n\t\t.get('set-cookie')\n\t\t?.split(',')\n\t\t.map((cookie) => cookie.trim());\n\n\tif (proxyCookies?.length) {\n\t\tproxyHeaders.set('set-cookie', proxyCookies.join(', '));\n\t}\n\n\treturn new Response(response.body, {\n\t\tstatus: response.status,\n\t\tstatusText: response.statusText,\n\t\theaders: proxyHeaders,\n\t});\n}\n\n/**\n * Returns a safe absolute redirect URL only if it shares the same origin as `safeBaseUrl`, preventing open redirects.\n *\n * @param {string | undefined | null} dangerousRedirect - The untrusted redirect path or URL.\n * @param {string} safeBaseUrl - The trusted base URL whose origin is used as the allowed origin.\n * @returns {string | null} The resolved URL string if safe, or `null`.\n */\nexport function toSafeRedirect(dangerousRedirect: string | undefined | null, safeBaseUrl: string): string | null {\n\tlet url: URL;\n\n\tif (!dangerousRedirect) {\n\t\treturn null;\n\t}\n\n\ttry {\n\t\turl = new URL(\n\t\t\tdangerousRedirect.startsWith('/') ? dangerousRedirect.slice(1) : dangerousRedirect,\n\t\t\tsafeBaseUrl && !safeBaseUrl.endsWith('/') ? `${safeBaseUrl}/` : safeBaseUrl,\n\t\t);\n\t} catch {\n\t\treturn null;\n\t}\n\n\tif (url.origin === new URL(safeBaseUrl).origin) {\n\t\treturn url.toString();\n\t}\n\n\treturn null;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{ConfigurationError as e,InternalError as t}from"../utils/errors.mjs";import{m as n}from"./oidc.mjs";import{decryptString as r,encryptString as i}from"../utils/crypto.mjs";var a=`strivacity-session-v1`,o=3900;function s(){return globalThis.sty??={},globalThis.sty.storage??=new Map,{async get(e){return Promise.resolve(globalThis.sty.storage?.get(e)??null)},async set(e,t){return globalThis.sty.storage?.set(e,t),Promise.resolve()},async delete(e){return globalThis.sty.storage?.delete(e),Promise.resolve()}}}function c(){return globalThis.sty??={},globalThis.sty.storage=new Map,{get:e=>Promise.resolve(globalThis.sty.storage.get(e)??null),set:(e,t)=>(globalThis.sty.storage.set(e,t),Promise.resolve()),delete:e=>(globalThis.sty.storage.delete(e),Promise.resolve()),deleteByLogoutToken:e=>{for(let[t,n]of globalThis.sty.storage){let r=JSON.parse(n)?.claims;(e.sid&&r?.sid===e.sid||e.sub&&r?.sub===e.sub)&&globalThis.sty.storage.delete(t)}return Promise.resolve()}}}function l(e,t,n){let r={httpOnly:!0,secure:!0,sameSite:`lax`,path:`/`,...n?.defaultCookieOptions};return e.getSessionId||=async(t,n)=>n?_((await e.toRequest(n)).headers.get(`cookie`))[t]:null,{async get(n,r){let i=await e.getSessionId(n,r);return i?await t.get(i):null},async set(i,a,o){let s=await e.getSessionId(i,o);s||(s=n?.uuidGenerator?.()??globalThis.crypto.randomUUID(),y(o,v(i,s,r))),await t.set(s,a)},async delete(n,i){let a=await e.getSessionId(n,i);a&&await t.delete(a),y(i,v(n,``,{...r,expires:new Date(0)}))},async deleteByLogoutToken(e){await t.deleteByLogoutToken?.(e)}}}function u(e,t,n){let s={httpOnly:!0,secure:!0,sameSite:`lax`,path:`/`,...n?.defaultCookieOptions};async function c(e,n){return e?_((await t.toRequest(e)).headers.get(`cookie`))[n]:void 0}let l={async get(t,n){let i=await c(n,t);if(i)return await r(i,e,a);let o=[];for(let e=0;;e++){let r=await c(n,`${t}.${e}`);if(!r)break;o.push(r)}return o.length===0?null:await r(o.join(``),e,a)},async set(t,n,r){await l.delete(t,r);let c=await i(n,e,a);if(c.length<=3900)y(r,v(t,c,s));else for(let e=0;e*o<c.length;e++)y(r,v(`${t}.${e}`,c.slice(e*o,(e+1)*o),s))},async delete(e,t){let n={...s,expires:new Date(0)};y(t,v(e,``,n));for(let r=0;await c(t,`${e}.${r}`);r++)y(t,v(`${e}.${r}`,``,n))}};return l}var d=new Set([`transfer-encoding`,`connection`,`keep-alive`,`content-encoding`]),f=`sty.returnTo`,p=`http://schemas.openid.net/event/backchannel-logout`,m=2592e3,h=new WeakMap;function g(t,r){if(r.postLoginRedirectUri??=new URL(r.redirectUri).origin,r.postLogoutRedirectUri??=new URL(r.redirectUri).origin,r.cookieMaxAge??=m,!r.storage){if(!r.secret)throw new e(`Missing SDK option: secret`);r.storage=u(r.secret,t,{defaultCookieOptions:{maxAge:r.cookieMaxAge}})}return r.stateStorage??=s(),r.urlHandler??=async()=>Promise.resolve(void 0),r.authUrlPrefix??=`/auth`,r.loginUri??=`/login`,r.serverSessionUri===void 0&&(r.serverSessionUri??=`${r.authUrlPrefix}/login`),n(r)}function _(e){let t={};if(!e)return t;for(let n of e.split(`;`)){let e=n.indexOf(`=`);if(e===-1)continue;let r=n.slice(0,e).trim(),i=n.slice(e+1).trim();if(r)try{t[r]=decodeURIComponent(i)}catch{t[r]=i}}return t}function v(e,t,n={}){let r=[`${e}=${encodeURIComponent(t)}`];return typeof n.maxAge==`number`&&r.push(`Max-Age=${Math.floor(n.maxAge)}`),n.expires&&r.push(`Expires=${n.expires.toUTCString()}`),r.push(`Path=${n.path??`/`}`),n.domain&&r.push(`Domain=${n.domain}`),n.sameSite&&r.push(`SameSite=${n.sameSite.charAt(0).toUpperCase()}${n.sameSite.slice(1)}`),n.secure&&r.push(`Secure`),n.httpOnly&&r.push(`HttpOnly`),r.join(`; `)}function y(e,n){if(typeof e!=`object`||!e)throw new t(`Server adapter events must be objects to track outgoing cookies`);let r=h.get(e)??[];r.push(n),h.set(e,r)}function b(e,n){if(typeof e!=`object`||!e)throw new t(`Server adapter events must be objects to track outgoing cookies`);let r=h.get(e);if(r?.length){for(let e of r)n.headers.append(`set-cookie`,e);h.delete(e)}return n}function x(e){let t=new Headers;for(let[n,r]of e.headers.entries())n.toLowerCase()!==`set-cookie`&&(d.has(n.toLowerCase())||t.set(n,r));let n=e.headers.get(`set-cookie`)?.split(`,`).map(e=>e.trim());return n?.length&&t.set(`set-cookie`,n.join(`, `)),new Response(e.body,{status:e.status,statusText:e.statusText,headers:t})}function S(e,t){let n;if(!e)return null;try{n=new URL(e.startsWith(`/`)?e.slice(1):e,t&&!t.endsWith(`/`)?`${t}/`:t)}catch{return null}return n.origin===new URL(t).origin?n.toString():null}export{l as _,b as a,x as c,S as d,o as f,s as g,c as h,f as i,y as l,u as m,m as n,g as o,a as p,d as r,_ as s,p as t,v as u};
|
|
2
|
+
//# sourceMappingURL=server.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.mjs","names":[],"sources":["../../src/storages/server.ts","../../src/utils/server.ts"],"sourcesContent":["import type { SDKStorage } from '../types/common';\nimport type { EncryptedCookieStorageOptions, ServerAdapter, ServerCookieOptions, ServerStorage, SessionIdCookieStorageOptions } from '../types/server';\nimport { encryptString, decryptString } from '../utils/crypto';\nimport { parseCookieHeader, pushSetCookie, serializeCookie } from '../utils/server';\n\nexport const COOKIE_CONTEXT = 'strivacity-session-v1';\nexport const COOKIE_CHUNK_SIZE = 3900;\n\n/**\n * Creates a simple in-memory state storage implementation, shared across all server adapters.\n *\n * @returns {SDKStorage} An object implementing the SDKStorage interface.\n */\nexport function createServerStateStorage(): SDKStorage {\n\tglobalThis.sty ??= {} as typeof globalThis.sty;\n\tglobalThis.sty.storage ??= new Map<string, string>();\n\n\treturn {\n\t\tasync get(key) {\n\t\t\treturn Promise.resolve(globalThis.sty.storage?.get(key) ?? null);\n\t\t},\n\t\tasync set(key, value) {\n\t\t\tglobalThis.sty.storage?.set(key, value);\n\n\t\t\treturn Promise.resolve();\n\t\t},\n\t\tasync delete(key) {\n\t\t\tglobalThis.sty.storage?.delete(key);\n\n\t\t\treturn Promise.resolve();\n\t\t},\n\t};\n}\n\n/**\n * In-memory global storage adapter for session data.\n * Not recommended for production use, as session data will be lost on server restart.\n *\n * @returns {ServerStorage} An object implementing the ServerStorage interface.\n */\nexport function createServerMemoryStorage(): ServerStorage {\n\tglobalThis.sty ??= {} as typeof globalThis.sty;\n\tglobalThis.sty.storage = new Map<string, string>();\n\n\treturn {\n\t\tget: (key) => {\n\t\t\treturn Promise.resolve(globalThis.sty.storage!.get(key) ?? null);\n\t\t},\n\t\tset: (key, value) => {\n\t\t\tglobalThis.sty.storage!.set(key, value);\n\n\t\t\treturn Promise.resolve();\n\t\t},\n\t\tdelete: (key) => {\n\t\t\tglobalThis.sty.storage!.delete(key);\n\n\t\t\treturn Promise.resolve();\n\t\t},\n\t\tdeleteByLogoutToken: (logoutToken) => {\n\t\t\tfor (const [mapKey, raw] of globalThis.sty.storage!) {\n\t\t\t\tconst claims = JSON.parse(raw)?.claims;\n\n\t\t\t\tif ((logoutToken.sid && claims?.sid === logoutToken.sid) || (logoutToken.sub && claims?.sub === logoutToken.sub)) {\n\t\t\t\t\tglobalThis.sty.storage!.delete(mapKey);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn Promise.resolve();\n\t\t},\n\t};\n}\n\n/**\n * Creates a session storage that puts a session-id value cookie on the client and keeping the actual session data in the given `storage`.\n *\n * @param {ServerAdapter<TEvent>} adapter - The framework adapter used to read the incoming request.\n * @param {ServerStorage<TEvent>} storage - The storage used to persist session data, keyed by a randomly generated session id.\n * @param {SessionIdCookieStorageOptions} [options] - Options for the session ID cookie, including default cookie attributes and a UUID generator function.\n * @param {Partial<ServerCookieOptions>} [options.defaultCookieOptions] - Default cookie attributes for the session ID cookie.\n * @param {() => string} [options.uuidGenerator] - Function to generate a new UUID for the session ID. Defaults to `() => crypto.randomUUID()`.\n * @returns {ServerStorage<TEvent>} An object implementing the `ServerStorage` interface for managing sessions indexed by a session-id cookie.\n */\nexport function createSessionIdCookieStorage<TEvent = unknown>(\n\tadapter: ServerAdapter<TEvent>,\n\tstorage: ServerStorage,\n\toptions?: SessionIdCookieStorageOptions,\n): ServerStorage<TEvent> {\n\tconst defaultCookieOptions: ServerCookieOptions = {\n\t\thttpOnly: true,\n\t\tsecure: true,\n\t\tsameSite: 'lax',\n\t\tpath: '/',\n\t\t...options?.defaultCookieOptions,\n\t};\n\n\tif (!adapter.getSessionId) {\n\t\tadapter.getSessionId = async (key: string, event?: TEvent) => {\n\t\t\tif (!event) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst request = await adapter.toRequest(event);\n\t\t\tconst cookies = parseCookieHeader(request.headers.get('cookie'));\n\n\t\t\treturn cookies[key];\n\t\t};\n\t}\n\n\treturn {\n\t\tasync get(key, event) {\n\t\t\tconst id = await adapter.getSessionId!(key, event);\n\n\t\t\treturn id ? await storage.get(id) : null;\n\t\t},\n\t\tasync set(key, value, event) {\n\t\t\tlet id = await adapter.getSessionId!(key, event);\n\n\t\t\tif (!id) {\n\t\t\t\tid = options?.uuidGenerator?.() ?? globalThis.crypto.randomUUID();\n\t\t\t\tpushSetCookie(event, serializeCookie(key, id, defaultCookieOptions));\n\t\t\t}\n\n\t\t\tawait storage.set(id, value);\n\t\t},\n\t\tasync delete(key, event) {\n\t\t\tconst id = await adapter.getSessionId!(key, event);\n\n\t\t\tif (id) {\n\t\t\t\tawait storage.delete(id);\n\t\t\t}\n\n\t\t\tpushSetCookie(event, serializeCookie(key, '', { ...defaultCookieOptions, expires: new Date(0) }));\n\t\t},\n\t\tasync deleteByLogoutToken(token) {\n\t\t\tawait storage.deleteByLogoutToken?.(token);\n\t\t},\n\t};\n}\n\n/**\n * Creates an encrypted session storage backed by cookies.\n * Built entirely on top of `adapter.toRequest`'s `Request` (reading the `cookie` header) and the outgoing cookie jar (writing `set-cookie` headers).\n *\n * @param {string} secret - The secret key used for encryption and decryption.\n * @param {ServerAdapter<TEvent>} adapter - The framework adapter used to read the incoming request.\n * @param {EncryptedCookieStorageOptions} [options] - Cookie attributes (maxAge, sameSite, etc.). `path` defaults to `'/'`.\n * @param {Partial<ServerCookieOptions>} [options.defaultCookieOptions] - Default cookie attributes for the session ID cookie.\n * @returns {ServerStorage<TEvent>} An object implementing the `ServerStorage` interface for managing encrypted session cookies.\n */\nexport function createEncryptedCookieStorage<TEvent = unknown>(\n\tsecret: string,\n\tadapter: ServerAdapter<TEvent>,\n\toptions?: EncryptedCookieStorageOptions,\n): ServerStorage<TEvent> {\n\tconst defaultCookieOptions: ServerCookieOptions = {\n\t\thttpOnly: true,\n\t\tsecure: true,\n\t\tsameSite: 'lax',\n\t\tpath: '/',\n\t\t...options?.defaultCookieOptions,\n\t};\n\n\tasync function getIncomingCookie(event: TEvent | undefined, name: string): Promise<string | undefined> {\n\t\tif (!event) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst request = await adapter.toRequest(event);\n\t\tconst cookies = parseCookieHeader(request.headers.get('cookie'));\n\n\t\treturn cookies[name];\n\t}\n\n\tconst storage: ServerStorage<TEvent> = {\n\t\tasync get(key, event) {\n\t\t\tconst cookie = await getIncomingCookie(event, key);\n\n\t\t\tif (cookie) {\n\t\t\t\t// NOTE: If the cookie is present, we can decrypt it directly without checking for chunks.\n\t\t\t\treturn await decryptString(cookie, secret, COOKIE_CONTEXT);\n\t\t\t}\n\n\t\t\t// NOTE: If the cookie is not present, we check for chunked cookies (e.g., `key.0`, `key.1`, etc.) and concatenate them before decryption.\n\t\t\tconst cookieChunks: Array<string> = [];\n\n\t\t\tfor (let i = 0; ; i++) {\n\t\t\t\tconst chunk = await getIncomingCookie(event, `${key}.${i}`);\n\n\t\t\t\tif (!chunk) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcookieChunks.push(chunk);\n\t\t\t}\n\n\t\t\tif (cookieChunks.length === 0) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\treturn await decryptString(cookieChunks.join(''), secret, COOKIE_CONTEXT);\n\t\t},\n\n\t\tasync set(key, value, event) {\n\t\t\t// NOTE: Delete existing cookie(s) first to avoid leaving old chunks behind\n\t\t\tawait storage.delete(key, event);\n\n\t\t\tconst encrypted = await encryptString(value, secret, COOKIE_CONTEXT);\n\n\t\t\tif (encrypted.length <= COOKIE_CHUNK_SIZE) {\n\t\t\t\tpushSetCookie(event, serializeCookie(key, encrypted, defaultCookieOptions));\n\t\t\t} else {\n\t\t\t\tfor (let i = 0; i * COOKIE_CHUNK_SIZE < encrypted.length; i++) {\n\t\t\t\t\tpushSetCookie(event, serializeCookie(`${key}.${i}`, encrypted.slice(i * COOKIE_CHUNK_SIZE, (i + 1) * COOKIE_CHUNK_SIZE), defaultCookieOptions));\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\tasync delete(key, event) {\n\t\t\tconst expiredOptions = { ...defaultCookieOptions, expires: new Date(0) };\n\n\t\t\tpushSetCookie(event, serializeCookie(key, '', expiredOptions));\n\n\t\t\tfor (let i = 0; await getIncomingCookie(event, `${key}.${i}`); i++) {\n\t\t\t\tpushSetCookie(event, serializeCookie(`${key}.${i}`, '', expiredOptions));\n\t\t\t}\n\t\t},\n\t};\n\n\treturn storage;\n}\n","import type { HttpClientResponse, SDKStorage, ServerCookieOptions, ServerAdapter, ServerSDKOptions, ServerStorage } from '../types';\nimport { getSDKOptions } from './oidc';\nimport { createServerStateStorage, createEncryptedCookieStorage } from '../storages/server';\nimport { ConfigurationError, InternalError } from './errors';\n\n/**\n * Disallowed headers that should not be proxied from the SDK to the client, as they may interfere with the response handling.\n */\nexport const DISALLOWED_PROXY_HEADERS = new Set(['transfer-encoding', 'connection', 'keep-alive', 'content-encoding']);\n\n/**\n * Returns with the returnTo cookie name used for storing the returnTo URL in the server SDK.\n */\nexport const RETURN_TO_COOKIE = 'sty.returnTo';\n\n/**\n * Backchannel logout event name used for identifying backchannel logout requests in the server SDK.\n */\nexport const BACKCHANNEL_LOGOUT_EVENT = 'http://schemas.openid.net/event/backchannel-logout';\n\n/**\n * Default cookie max age in seconds (30 days).\n */\nexport const DEFAULT_COOKIE_MAX_AGE = 30 * 24 * 60 * 60;\n\n/**\n * A WeakMap to store cookies for each request event, allowing for proper cookie management in server-side environments.\n */\nconst cookieJars = new WeakMap<object, Array<string>>();\n\n/**\n * Returns with the server SDK options merged with the provided options.\n *\n * @param {SDKInitConfig} options - The SDK initialization configuration.\n * @template InitOptions - The type of the SDK initialization configuration.\n * @template Options - The type of the SDK options.\n * @returns {Options} The merged SDK options.\n */\nexport function getServerSDKOptions<\n\tTEvent = unknown,\n\tStorage extends ServerStorage<TEvent> = ServerStorage<TEvent>,\n\tStateStorage extends SDKStorage = SDKStorage,\n\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n>(adapter: ServerAdapter<TEvent>, options: any): ServerSDKOptions<TEvent, Storage, StateStorage> {\n\toptions.postLoginRedirectUri ??= new URL(options.redirectUri).origin;\n\toptions.postLogoutRedirectUri ??= new URL(options.redirectUri).origin;\n\toptions.cookieMaxAge ??= DEFAULT_COOKIE_MAX_AGE;\n\n\tif (!options.storage) {\n\t\tif (!options.secret) {\n\t\t\tthrow new ConfigurationError('Missing SDK option: secret');\n\t\t}\n\n\t\toptions.storage = createEncryptedCookieStorage<TEvent>(options.secret, adapter, { defaultCookieOptions: { maxAge: options.cookieMaxAge } });\n\t}\n\n\toptions.stateStorage ??= createServerStateStorage();\n\toptions.urlHandler ??= async () => Promise.resolve(undefined);\n\toptions.authUrlPrefix ??= '/auth';\n\toptions.loginUri ??= '/login';\n\n\tif (typeof options.serverSessionUri === 'undefined') {\n\t\toptions.serverSessionUri ??= `${options.authUrlPrefix}/login`;\n\t}\n\n\treturn getSDKOptions(options);\n}\n\n/**\n * Parses a `Cookie` request header into a plain name/value map.\n *\n * @param {string | null | undefined} header - The raw `Cookie` header value.\n * @returns {Record<string, string>} The parsed cookies.\n */\nexport function parseCookieHeader(header: string | null | undefined): Record<string, string> {\n\tconst cookies: Record<string, string> = {};\n\n\tif (!header) {\n\t\treturn cookies;\n\t}\n\n\tfor (const part of header.split(';')) {\n\t\tconst index = part.indexOf('=');\n\n\t\tif (index === -1) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst name = part.slice(0, index).trim();\n\t\tconst value = part.slice(index + 1).trim();\n\n\t\tif (name) {\n\t\t\ttry {\n\t\t\t\tcookies[name] = decodeURIComponent(value);\n\t\t\t} catch {\n\t\t\t\tcookies[name] = value;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn cookies;\n}\n\n/**\n * Serializes a name/value pair into a `Set-Cookie` header value.\n *\n * @param {string} name - The cookie name.\n * @param {string} value - The cookie value.\n * @param {ServerCookieOptions} [options] - The cookie attributes.\n * @returns {string} The serialized `Set-Cookie` header value.\n */\nexport function serializeCookie(name: string, value: string, options: ServerCookieOptions = {}): string {\n\tconst segments = [`${name}=${encodeURIComponent(value)}`];\n\n\tif (typeof options.maxAge === 'number') {\n\t\tsegments.push(`Max-Age=${Math.floor(options.maxAge)}`);\n\t}\n\tif (options.expires) {\n\t\tsegments.push(`Expires=${options.expires.toUTCString()}`);\n\t}\n\n\tsegments.push(`Path=${options.path ?? '/'}`);\n\n\tif (options.domain) {\n\t\tsegments.push(`Domain=${options.domain}`);\n\t}\n\tif (options.sameSite) {\n\t\tsegments.push(`SameSite=${options.sameSite.charAt(0).toUpperCase()}${options.sameSite.slice(1)}`);\n\t}\n\tif (options.secure) {\n\t\tsegments.push('Secure');\n\t}\n\tif (options.httpOnly) {\n\t\tsegments.push('HttpOnly');\n\t}\n\n\treturn segments.join('; ');\n}\n\n/**\n * Pushes a `Set-Cookie` header value into the cookie jar for the given event.\n *\n * @param {unknown} event - The framework-native request event.\n * @param {string} header - The `Set-Cookie` header value to push.\n */\nexport function pushSetCookie(event: unknown, header: string): void {\n\tif (event === null || typeof event !== 'object') {\n\t\tthrow new InternalError('Server adapter events must be objects to track outgoing cookies');\n\t}\n\n\tconst jar = cookieJars.get(event) ?? [];\n\tjar.push(header);\n\tcookieJars.set(event, jar);\n}\n\n/**\n * Flushes the accumulated `Set-Cookie` headers from the cookie jar into the provided `Response`.\n *\n * @param {unknown} event - The framework-native request event.\n * @param {Response} response - The `Response` object to append the `Set-Cookie` headers to.\n * @returns {Response} The modified `Response` with the appended `Set-Cookie` headers.\n */\nexport function flushSetCookies(event: unknown, response: Response): Response {\n\tif (event === null || typeof event !== 'object') {\n\t\tthrow new InternalError('Server adapter events must be objects to track outgoing cookies');\n\t}\n\n\tconst jar = cookieJars.get(event);\n\n\tif (jar?.length) {\n\t\tfor (const header of jar) {\n\t\t\tresponse.headers.append('set-cookie', header);\n\t\t}\n\n\t\tcookieJars.delete(event);\n\t}\n\n\treturn response;\n}\n\n/**\n * Proxies an `HttpClientResponse` to a Web `Response`, preserving headers and status code.\n *\n * @param {HttpClientResponse<T>} response - The `HttpClientResponse` to proxy.\n * @returns {Response} A `Response` object representing the proxied response.\n */\nexport function proxyResponse<T = unknown>(response: HttpClientResponse<T>): Response {\n\tconst proxyHeaders = new Headers();\n\n\tfor (const [key, value] of response.headers.entries()) {\n\t\tif (key.toLowerCase() === 'set-cookie') {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (!DISALLOWED_PROXY_HEADERS.has(key.toLowerCase())) {\n\t\t\tproxyHeaders.set(key, value);\n\t\t}\n\t}\n\n\tconst proxyCookies = response.headers\n\t\t.get('set-cookie')\n\t\t?.split(',')\n\t\t.map((cookie) => cookie.trim());\n\n\tif (proxyCookies?.length) {\n\t\tproxyHeaders.set('set-cookie', proxyCookies.join(', '));\n\t}\n\n\treturn new Response(response.body, {\n\t\tstatus: response.status,\n\t\tstatusText: response.statusText,\n\t\theaders: proxyHeaders,\n\t});\n}\n\n/**\n * Returns a safe absolute redirect URL only if it shares the same origin as `safeBaseUrl`, preventing open redirects.\n *\n * @param {string | undefined | null} dangerousRedirect - The untrusted redirect path or URL.\n * @param {string} safeBaseUrl - The trusted base URL whose origin is used as the allowed origin.\n * @returns {string | null} The resolved URL string if safe, or `null`.\n */\nexport function toSafeRedirect(dangerousRedirect: string | undefined | null, safeBaseUrl: string): string | null {\n\tlet url: URL;\n\n\tif (!dangerousRedirect) {\n\t\treturn null;\n\t}\n\n\ttry {\n\t\turl = new URL(\n\t\t\tdangerousRedirect.startsWith('/') ? dangerousRedirect.slice(1) : dangerousRedirect,\n\t\t\tsafeBaseUrl && !safeBaseUrl.endsWith('/') ? `${safeBaseUrl}/` : safeBaseUrl,\n\t\t);\n\t} catch {\n\t\treturn null;\n\t}\n\n\tif (url.origin === new URL(safeBaseUrl).origin) {\n\t\treturn url.toString();\n\t}\n\n\treturn null;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../utils/errors.cjs"),t=require("../utils/session.cjs"),n=require("../assets/oidc.cjs");function r(r,i){let a={init:null,refresh:null,revoke:null,logout:null,tokenExchange:new Map},o={accessTokenExpired:new Set,init:new Set,loggedIn:new Set,sessionUpdated:new Set,sessionCleared:new Set,loginInitiated:new Set,flowInitiated:new Set,logoutInitiated:new Set,sessionLoaded:new Set,tokenRefreshed:new Set,tokenRefreshFailed:new Set,tokenRevoked:new Set,tokenRevokeFailed:new Set};function s(e,t){for(let n of o[e])n(...t)}function c(e,t){return o[e].add(t),{dispose:()=>o[e].delete(t)}}function l(e){for(let t in o)o[t].add(e);return{dispose:()=>{for(let t in o)o[t].delete(e)}}}async function u(){return await m(),r.session}async function d(e){await m(),e.id_token&&!e.claims&&(e.claims=await n.v({idToken:e.id_token,options:i})),i.serverSessionUri||await i.storage.set(i.storageTokenName,t.serializeSession(e)),r.session=e,s(`sessionUpdated`,[{idToken:r.session.id_token,accessToken:r.session.access_token,refreshToken:r.session.refresh_token,claims:r.session.claims}])}async function f(){await m(),i.serverSessionUri||await i.storage.delete(i.storageTokenName),r.session=null,s(`sessionCleared`,[])}async function p(e={autoRefresh:i.autoRefresh}){if(r.session?.access_token&&!t.isSessionExpired(r.session))return!0;if(e?.autoRefresh&&r.session?.refresh_token)try{await _()}catch{return!1}return!t.isSessionExpired(r.session)}async function m(){if(!r.initialized)return a.init||=(async()=>{try{if(!i.issuer){let t=new e.ConfigurationError(`Missing option: issuer`);throw i.logging?.error(`Required option missing`,t),t}if(!i.clientId){let t=new e.ConfigurationError(`Missing option: clientId`);throw i.logging?.error(`Required option missing`,t),t}if(!i.redirectUri){let t=new e.ConfigurationError(`Missing option: redirectUri`);throw i.logging?.error(`Required option missing`,t),t}if(i.scopes&&!Array.isArray(i.scopes)){let t=new e.ConfigurationError(`Invalid option: scopes`);throw i.logging?.error(`Invalid option provided`,t),t}i.serverSessionUri||(r.session=t.loadSession(await i.storage.get(i.storageTokenName))),r.initialized=!0,s(`init`,[]),i.logging?.debug(`SDK initialized`),!r.session&&!i.serverSessionUri&&i.logging?.debug(`No session found in storage`),r.session?.access_token&&(s(`sessionLoaded`,[{idToken:r.session.id_token,accessToken:r.session.access_token,refreshToken:r.session.refresh_token,claims:r.session.claims}]),i.logging?.debug(`Session loaded from storage`)),r.session?.access_token&&t.isSessionExpired(r.session)&&(s(`accessTokenExpired`,[{accessToken:r.session.access_token,refreshToken:r.session.refresh_token}]),i.logging?.debug(`Access token has expired`))}finally{a.init=null}})(),a.init}async function h(t={}){await m();let r=t.state??``,o=a.tokenExchange.get(r);if(o)return o;let c=(async()=>{i.logging?.debug(`Exchanging authorization code for tokens`);try{let r=await n.a({params:t,options:i});if(!r.access_token)throw new e.ProtocolError(`Missing access_token`);await d(r),i.logging?.debug(`Token exchange successful`),s(`loggedIn`,[{idToken:r.id_token,accessToken:r.access_token,refreshToken:r.refresh_token,claims:r.claims}]),i.logging&&(i.logging.xEventId=void 0,i.logging.info(`Login successful`))}catch(e){throw i.logging?.error(`Token exchange failed`,e),e}finally{a.tokenExchange.delete(r)}})();return a.tokenExchange.set(r,c),c}async function g(e){await m();let t=e??globalThis.window?.location.href;await h(await i.callbackHandler(t,i.responseMode))}async function _(){if(await m(),a.refresh)return a.refresh;if(a.revoke)try{await a.revoke}catch{}if(a.logout)try{await a.logout}catch{}if(i.logging?.debug(`Attempting to refresh session`),typeof r.session?.refresh_token!=`string`){i.logging?.debug(`Refresh called without refresh token`);return}return a.refresh=(async()=>{try{await d(await n.h({refreshToken:r.session.refresh_token,options:i,expectedSub:r.session?.claims?.sub})),s(`tokenRefreshed`,[{idToken:r.session?.id_token,accessToken:r.session?.access_token,refreshToken:r.session?.refresh_token,claims:r.session?.claims}]),i.logging?.debug(`Session refresh successful`)}catch(t){let n=r.session?.refresh_token;throw!(t instanceof e.NetworkError)&&!(t instanceof e.ServerError)&&await f(),s(`tokenRefreshFailed`,[{refreshToken:n}]),i.logging?.error(`Session refresh failed`,t),t}finally{a.refresh=null}})(),a.refresh}async function v(){if(await m(),a.revoke)return a.revoke;if(a.refresh)try{await a.refresh}catch{}if(a.logout)try{await a.logout}catch{}return a.revoke=(async()=>{try{r.session?.refresh_token?i.logging?.debug(`Attempting to revoke refresh token`):r.session?.access_token&&i.logging?.debug(`Attempting to revoke access token`);let e=r.session;if(await f(),!e?.access_token&&!e?.refresh_token){i.logging?.debug(`Revoke called without session`);return}let t=e.refresh_token?`refresh_token`:`access_token`,a=t===`refresh_token`?e.refresh_token:e.access_token;try{await n.g({tokenTypeHint:t,token:a,options:i}),t===`refresh_token`?(s(`tokenRevoked`,[{token:e.refresh_token,tokenTypeHint:`refresh_token`}]),i.logging?.info(`Refresh token successfully revoked`)):(s(`tokenRevoked`,[{token:e.access_token,tokenTypeHint:`access_token`}]),i.logging?.info(`Access token successfully revoked`))}catch(n){throw t===`refresh_token`?s(`tokenRevokeFailed`,[{token:e.refresh_token,tokenTypeHint:`refresh_token`}]):s(`tokenRevokeFailed`,[{token:e.access_token,tokenTypeHint:`access_token`}]),i.logging?.error(`Token revocation failed`,n),n}}finally{a.revoke=null}})(),a.revoke}async function y(e){if(await m(),a.logout)return a.logout;if(a.revoke)try{await a.revoke}catch{}if(a.refresh)try{await a.refresh}catch{}return a.logout=(async()=>{try{i.logging?.debug(`Attempting to logout`);let t=r.session;if(await f(),s(`logoutInitiated`,[{idToken:t?.id_token,claims:t?.claims}]),i.logging?.debug(`Logout initiated`),!t?.id_token){i.logging?.debug(`Logout called without id token`);return}try{let r=await n.p(i),a=n.n({url:r.end_session_endpoint,idToken:t.id_token,postLogoutRedirectUri:e?.postLogoutRedirectUri});await i.urlHandler(a,e)}catch(e){i.logging?.error(`Unable to redirect to the end-session endpoint`,e)}}finally{a.logout=null}})(),a.logout}return{dispatchEvent:s,subscribeToEvent:c,subscribeToAllEvents:l,getSession:u,updateSession:d,cleanupSession:f,checkAuthentication:p,init:m,tokenExchange:h,handleCallback:g,refresh:_,revoke:v,logout:y}}exports.createBaseFlow=r;
|
|
2
|
+
//# sourceMappingURL=base.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base.cjs","names":[],"sources":["../../src/flows/base.ts"],"sourcesContent":["import type { EventFunctions, ExtraRequestArgs, FlowState, SDK, SDKOptions, SessionData } from '../types/oidc';\nimport { buildEndSessionUrl, exchangeCode, getDiscoveryDocument, refreshToken, revokeToken, verifyIdToken } from '../utils/oidc';\nimport { loadSession, serializeSession, isSessionExpired } from '../utils/session';\nimport { ConfigurationError, NetworkError, ProtocolError, ServerError } from '../utils/errors';\n\n/**\n * Creates a base flow for the Strivacity SDK, providing common functionality for managing authentication sessions.\n *\n * @param flowState - The initial state of the flow, including session data and initialization status.\n * @param options - The SDK options, including issuer, clientId, redirectUri, scopes, and storage configuration.\n * @template URLHandlerParams - The type of additional request arguments for URL handling.\n * @returns An object implementing the SDK interface, with methods for initializing the flow, managing sessions, and handling authentication events.\n */\nexport function createBaseFlow<URLHandlerParams extends ExtraRequestArgs = ExtraRequestArgs>(flowState: FlowState, options: SDKOptions) {\n\tconst promises: Record<'init' | 'refresh' | 'revoke' | 'logout', Promise<void> | null> & { tokenExchange: Map<string, Promise<void>> } = {\n\t\tinit: null,\n\t\trefresh: null,\n\t\trevoke: null,\n\t\tlogout: null,\n\t\ttokenExchange: new Map(),\n\t};\n\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\tconst eventCallbacks: Record<keyof EventFunctions, Set<(...args: Array<any>) => Promise<void> | void>> = {\n\t\taccessTokenExpired: new Set(),\n\t\tinit: new Set(),\n\t\tloggedIn: new Set(),\n\t\tsessionUpdated: new Set(),\n\t\tsessionCleared: new Set(),\n\t\tloginInitiated: new Set(),\n\t\tflowInitiated: new Set(),\n\t\tlogoutInitiated: new Set(),\n\t\tsessionLoaded: new Set(),\n\t\ttokenRefreshed: new Set(),\n\t\ttokenRefreshFailed: new Set(),\n\t\ttokenRevoked: new Set(),\n\t\ttokenRevokeFailed: new Set(),\n\t};\n\n\tfunction dispatchEvent<T extends keyof EventFunctions>(eventName: T, args: Parameters<EventFunctions[T]>): void {\n\t\tfor (const fn of eventCallbacks[eventName]) {\n\t\t\tvoid fn(...args);\n\t\t}\n\t}\n\n\tfunction subscribeToEvent<T extends keyof EventFunctions>(\n\t\teventName: T,\n\t\tcallbackFn: (...params: Parameters<EventFunctions[T]>) => Promise<void> | void,\n\t): ReturnType<SDK<URLHandlerParams>['subscribeToEvent']> {\n\t\teventCallbacks[eventName].add(callbackFn);\n\t\treturn { dispose: () => eventCallbacks[eventName].delete(callbackFn) };\n\t}\n\n\tfunction subscribeToAllEvents(callbackFn: (...params: Array<unknown>) => Promise<void> | void): ReturnType<SDK<URLHandlerParams>['subscribeToAllEvents']> {\n\t\tfor (const eventName in eventCallbacks) {\n\t\t\teventCallbacks[eventName as keyof EventFunctions].add(callbackFn);\n\t\t}\n\n\t\treturn {\n\t\t\tdispose: () => {\n\t\t\t\tfor (const eventName in eventCallbacks) {\n\t\t\t\t\teventCallbacks[eventName as keyof EventFunctions].delete(callbackFn);\n\t\t\t\t}\n\t\t\t},\n\t\t};\n\t}\n\n\tasync function getSession(): Promise<SessionData | null> {\n\t\tawait init();\n\n\t\treturn flowState.session;\n\t}\n\n\tasync function updateSession(newData: SessionData): ReturnType<SDK<URLHandlerParams>['updateSession']> {\n\t\tawait init();\n\n\t\t// NOTE: only unverified callers (e.g. direct API use) need validating here\n\t\tif (newData.id_token && !newData.claims) {\n\t\t\tnewData.claims = await verifyIdToken({ idToken: newData.id_token, options });\n\t\t}\n\n\t\tif (!options.serverSessionUri) {\n\t\t\tawait options.storage.set(options.storageTokenName, serializeSession(newData));\n\t\t}\n\n\t\tflowState.session = newData;\n\n\t\tdispatchEvent('sessionUpdated', [\n\t\t\t{\n\t\t\t\tidToken: flowState.session.id_token,\n\t\t\t\taccessToken: flowState.session.access_token,\n\t\t\t\trefreshToken: flowState.session.refresh_token,\n\t\t\t\tclaims: flowState.session.claims,\n\t\t\t},\n\t\t]);\n\t}\n\n\tasync function cleanupSession(): ReturnType<SDK<URLHandlerParams>['cleanupSession']> {\n\t\tawait init();\n\n\t\tif (!options.serverSessionUri) {\n\t\t\tawait options.storage.delete(options.storageTokenName);\n\t\t}\n\n\t\tflowState.session = null;\n\n\t\tdispatchEvent('sessionCleared', []);\n\t}\n\n\tasync function checkAuthentication(\n\t\tparams: { autoRefresh: boolean } = { autoRefresh: options.autoRefresh },\n\t): ReturnType<SDK<URLHandlerParams>['checkAuthentication']> {\n\t\tif (flowState.session?.access_token && !isSessionExpired(flowState.session)) {\n\t\t\treturn true;\n\t\t}\n\n\t\tif (params?.autoRefresh && flowState.session?.refresh_token) {\n\t\t\ttry {\n\t\t\t\tawait refresh();\n\t\t\t} catch {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn !isSessionExpired(flowState.session);\n\t}\n\n\tasync function init(): ReturnType<SDK<URLHandlerParams>['init']> {\n\t\tif (flowState.initialized) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (promises.init) {\n\t\t\treturn promises.init;\n\t\t}\n\n\t\tpromises.init = (async () => {\n\t\t\ttry {\n\t\t\t\tif (!options.issuer) {\n\t\t\t\t\tconst error = new ConfigurationError('Missing option: issuer');\n\t\t\t\t\toptions.logging?.error('Required option missing', error);\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t\tif (!options.clientId) {\n\t\t\t\t\tconst error = new ConfigurationError('Missing option: clientId');\n\t\t\t\t\toptions.logging?.error('Required option missing', error);\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t\tif (!options.redirectUri) {\n\t\t\t\t\tconst error = new ConfigurationError('Missing option: redirectUri');\n\t\t\t\t\toptions.logging?.error('Required option missing', error);\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t\tif (options.scopes && !Array.isArray(options.scopes)) {\n\t\t\t\t\tconst error = new ConfigurationError('Invalid option: scopes');\n\t\t\t\t\toptions.logging?.error('Invalid option provided', error);\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\n\t\t\t\tif (!options.serverSessionUri) {\n\t\t\t\t\tflowState.session = loadSession(await options.storage.get(options.storageTokenName));\n\t\t\t\t}\n\n\t\t\t\tflowState.initialized = true;\n\n\t\t\t\tdispatchEvent('init', []);\n\t\t\t\toptions.logging?.debug('SDK initialized');\n\n\t\t\t\tif (!flowState.session && !options.serverSessionUri) {\n\t\t\t\t\toptions.logging?.debug('No session found in storage');\n\t\t\t\t}\n\n\t\t\t\tif (flowState.session?.access_token) {\n\t\t\t\t\tdispatchEvent('sessionLoaded', [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tidToken: flowState.session.id_token,\n\t\t\t\t\t\t\taccessToken: flowState.session.access_token,\n\t\t\t\t\t\t\trefreshToken: flowState.session.refresh_token,\n\t\t\t\t\t\t\tclaims: flowState.session.claims,\n\t\t\t\t\t\t},\n\t\t\t\t\t]);\n\t\t\t\t\toptions.logging?.debug('Session loaded from storage');\n\t\t\t\t}\n\n\t\t\t\tif (flowState.session?.access_token && isSessionExpired(flowState.session)) {\n\t\t\t\t\tdispatchEvent('accessTokenExpired', [{ accessToken: flowState.session.access_token, refreshToken: flowState.session.refresh_token }]);\n\t\t\t\t\toptions.logging?.debug('Access token has expired');\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\tpromises.init = null;\n\t\t\t}\n\t\t})();\n\n\t\treturn promises.init;\n\t}\n\n\tasync function tokenExchange(params: Parameters<SDK<URLHandlerParams>['tokenExchange']>[0] = {}): ReturnType<SDK<URLHandlerParams>['tokenExchange']> {\n\t\tawait init();\n\n\t\tconst exchangeKey = params.state ?? '';\n\t\tconst inFlight = promises.tokenExchange.get(exchangeKey);\n\n\t\tif (inFlight) {\n\t\t\treturn inFlight;\n\t\t}\n\n\t\tconst exchangePromise = (async () => {\n\t\t\toptions.logging?.debug('Exchanging authorization code for tokens');\n\n\t\t\ttry {\n\t\t\t\tconst session = await exchangeCode({ params, options });\n\n\t\t\t\tif (!session.access_token) {\n\t\t\t\t\tthrow new ProtocolError('Missing access_token');\n\t\t\t\t}\n\n\t\t\t\tawait updateSession(session);\n\n\t\t\t\toptions.logging?.debug('Token exchange successful');\n\n\t\t\t\tdispatchEvent('loggedIn', [\n\t\t\t\t\t{ idToken: session.id_token, accessToken: session.access_token, refreshToken: session.refresh_token, claims: session.claims },\n\t\t\t\t]);\n\n\t\t\t\tif (options.logging) {\n\t\t\t\t\toptions.logging.xEventId = undefined;\n\t\t\t\t\toptions.logging.info('Login successful');\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\toptions.logging?.error('Token exchange failed', error);\n\t\t\t\tthrow error;\n\t\t\t} finally {\n\t\t\t\tpromises.tokenExchange.delete(exchangeKey);\n\t\t\t}\n\t\t})();\n\n\t\tpromises.tokenExchange.set(exchangeKey, exchangePromise);\n\n\t\treturn exchangePromise;\n\t}\n\n\tasync function handleCallback(url?: string | URL): ReturnType<SDK<URLHandlerParams>['handleCallback']> {\n\t\tawait init();\n\n\t\tconst callbackUrl = url ?? globalThis.window?.location.href;\n\t\tconst params = (await options.callbackHandler(callbackUrl, options.responseMode)) as Record<string, string>;\n\n\t\tawait tokenExchange(params);\n\t}\n\n\tasync function refresh(): ReturnType<SDK<URLHandlerParams>['refresh']> {\n\t\tawait init();\n\n\t\tif (promises.refresh) {\n\t\t\treturn promises.refresh;\n\t\t}\n\n\t\tif (promises.revoke) {\n\t\t\ttry {\n\t\t\t\tawait promises.revoke;\n\t\t\t} catch {}\n\t\t}\n\n\t\tif (promises.logout) {\n\t\t\ttry {\n\t\t\t\tawait promises.logout;\n\t\t\t} catch {}\n\t\t}\n\n\t\toptions.logging?.debug('Attempting to refresh session');\n\n\t\tif (typeof flowState.session?.refresh_token !== 'string') {\n\t\t\toptions.logging?.debug('Refresh called without refresh token');\n\t\t\treturn;\n\t\t}\n\n\t\tpromises.refresh = (async () => {\n\t\t\ttry {\n\t\t\t\tconst session = await refreshToken({ refreshToken: flowState.session!.refresh_token!, options, expectedSub: flowState.session?.claims?.sub });\n\t\t\t\tawait updateSession(session);\n\n\t\t\t\tdispatchEvent('tokenRefreshed', [\n\t\t\t\t\t{\n\t\t\t\t\t\tidToken: flowState.session?.id_token,\n\t\t\t\t\t\taccessToken: flowState.session?.access_token,\n\t\t\t\t\t\trefreshToken: flowState.session?.refresh_token,\n\t\t\t\t\t\tclaims: flowState.session?.claims,\n\t\t\t\t\t},\n\t\t\t\t]);\n\t\t\t\toptions.logging?.debug('Session refresh successful');\n\t\t\t} catch (error) {\n\t\t\t\tconst failedRefreshToken = flowState.session?.refresh_token;\n\n\t\t\t\t// NOTE: Transient Network/Server failures must not destroy a session that could still be refreshed later.\n\t\t\t\tif (!(error instanceof NetworkError) && !(error instanceof ServerError)) {\n\t\t\t\t\tawait cleanupSession();\n\t\t\t\t}\n\n\t\t\t\tdispatchEvent('tokenRefreshFailed', [{ refreshToken: failedRefreshToken }]);\n\t\t\t\toptions.logging?.error('Session refresh failed', error);\n\n\t\t\t\tthrow error;\n\t\t\t} finally {\n\t\t\t\tpromises.refresh = null;\n\t\t\t}\n\t\t})();\n\n\t\treturn promises.refresh;\n\t}\n\n\tasync function revoke(): ReturnType<SDK<URLHandlerParams>['revoke']> {\n\t\tawait init();\n\n\t\tif (promises.revoke) {\n\t\t\treturn promises.revoke;\n\t\t}\n\n\t\tif (promises.refresh) {\n\t\t\ttry {\n\t\t\t\tawait promises.refresh;\n\t\t\t} catch {}\n\t\t}\n\n\t\tif (promises.logout) {\n\t\t\ttry {\n\t\t\t\tawait promises.logout;\n\t\t\t} catch {}\n\t\t}\n\n\t\tpromises.revoke = (async () => {\n\t\t\ttry {\n\t\t\t\tif (flowState.session?.refresh_token) {\n\t\t\t\t\toptions.logging?.debug('Attempting to revoke refresh token');\n\t\t\t\t} else if (flowState.session?.access_token) {\n\t\t\t\t\toptions.logging?.debug('Attempting to revoke access token');\n\t\t\t\t}\n\n\t\t\t\t// NOTE: Cleanup session before revocation\n\t\t\t\tconst currentSession = flowState.session;\n\t\t\t\tawait cleanupSession();\n\n\t\t\t\tif (!currentSession?.access_token && !currentSession?.refresh_token) {\n\t\t\t\t\toptions.logging?.debug('Revoke called without session');\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst tokenTypeHint = currentSession.refresh_token ? 'refresh_token' : 'access_token';\n\t\t\t\tconst token = (tokenTypeHint === 'refresh_token' ? currentSession.refresh_token : currentSession.access_token)!;\n\n\t\t\t\ttry {\n\t\t\t\t\tawait revokeToken({ tokenTypeHint, token, options });\n\n\t\t\t\t\tif (tokenTypeHint === 'refresh_token') {\n\t\t\t\t\t\tdispatchEvent('tokenRevoked', [{ token: currentSession.refresh_token, tokenTypeHint: 'refresh_token' }]);\n\t\t\t\t\t\toptions.logging?.info('Refresh token successfully revoked');\n\t\t\t\t\t} else {\n\t\t\t\t\t\tdispatchEvent('tokenRevoked', [{ token: currentSession.access_token, tokenTypeHint: 'access_token' }]);\n\t\t\t\t\t\toptions.logging?.info('Access token successfully revoked');\n\t\t\t\t\t}\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (tokenTypeHint === 'refresh_token') {\n\t\t\t\t\t\tdispatchEvent('tokenRevokeFailed', [{ token: currentSession.refresh_token, tokenTypeHint: 'refresh_token' }]);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tdispatchEvent('tokenRevokeFailed', [{ token: currentSession.access_token, tokenTypeHint: 'access_token' }]);\n\t\t\t\t\t}\n\n\t\t\t\t\toptions.logging?.error('Token revocation failed', error);\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\tpromises.revoke = null;\n\t\t\t}\n\t\t})();\n\n\t\treturn promises.revoke;\n\t}\n\n\tasync function logout(params?: Parameters<SDK<URLHandlerParams>['logout']>[0]): ReturnType<SDK<URLHandlerParams>['logout']> {\n\t\tawait init();\n\n\t\tif (promises.logout) {\n\t\t\treturn promises.logout;\n\t\t}\n\n\t\tif (promises.revoke) {\n\t\t\ttry {\n\t\t\t\tawait promises.revoke;\n\t\t\t} catch {}\n\t\t}\n\n\t\tif (promises.refresh) {\n\t\t\ttry {\n\t\t\t\tawait promises.refresh;\n\t\t\t} catch {}\n\t\t}\n\n\t\tpromises.logout = (async () => {\n\t\t\ttry {\n\t\t\t\toptions.logging?.debug('Attempting to logout');\n\n\t\t\t\t// NOTE: Cleanup session before logout\n\t\t\t\tconst currentSession = flowState.session;\n\t\t\t\tawait cleanupSession();\n\n\t\t\t\tdispatchEvent('logoutInitiated', [{ idToken: currentSession?.id_token, claims: currentSession?.claims }]);\n\t\t\t\toptions.logging?.debug('Logout initiated');\n\n\t\t\t\tif (!currentSession?.id_token) {\n\t\t\t\t\toptions.logging?.debug('Logout called without id token');\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tconst metadata = await getDiscoveryDocument(options);\n\t\t\t\t\tconst logoutUrl = buildEndSessionUrl({\n\t\t\t\t\t\turl: metadata.end_session_endpoint,\n\t\t\t\t\t\tidToken: currentSession.id_token,\n\t\t\t\t\t\tpostLogoutRedirectUri: params?.postLogoutRedirectUri,\n\t\t\t\t\t});\n\n\t\t\t\t\tawait options.urlHandler(logoutUrl, params);\n\t\t\t\t} catch (error) {\n\t\t\t\t\toptions.logging?.error('Unable to redirect to the end-session endpoint', error);\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\tpromises.logout = null;\n\t\t\t}\n\t\t})();\n\n\t\treturn promises.logout;\n\t}\n\n\treturn {\n\t\tdispatchEvent,\n\t\tsubscribeToEvent,\n\t\tsubscribeToAllEvents,\n\t\tgetSession,\n\t\tupdateSession,\n\t\tcleanupSession,\n\t\tcheckAuthentication,\n\t\tinit,\n\t\ttokenExchange,\n\t\thandleCallback,\n\t\trefresh,\n\t\trevoke,\n\t\tlogout,\n\t};\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { EventFunctions, ExtraRequestArgs, FlowState, SDK, SDKOptions, SessionData } from '../types/oidc';
|
|
2
|
+
/**
|
|
3
|
+
* Creates a base flow for the Strivacity SDK, providing common functionality for managing authentication sessions.
|
|
4
|
+
*
|
|
5
|
+
* @param flowState - The initial state of the flow, including session data and initialization status.
|
|
6
|
+
* @param options - The SDK options, including issuer, clientId, redirectUri, scopes, and storage configuration.
|
|
7
|
+
* @template URLHandlerParams - The type of additional request arguments for URL handling.
|
|
8
|
+
* @returns An object implementing the SDK interface, with methods for initializing the flow, managing sessions, and handling authentication events.
|
|
9
|
+
*/
|
|
10
|
+
export declare function createBaseFlow<URLHandlerParams extends ExtraRequestArgs = ExtraRequestArgs>(flowState: FlowState, options: SDKOptions): {
|
|
11
|
+
dispatchEvent: <T extends keyof EventFunctions>(eventName: T, args: Parameters<EventFunctions[T]>) => void;
|
|
12
|
+
subscribeToEvent: <T extends keyof EventFunctions>(eventName: T, callbackFn: (...params: Parameters<EventFunctions[T]>) => Promise<void> | void) => ReturnType<SDK<URLHandlerParams>["subscribeToEvent"]>;
|
|
13
|
+
subscribeToAllEvents: (callbackFn: (...params: Array<unknown>) => Promise<void> | void) => ReturnType<SDK<URLHandlerParams>["subscribeToAllEvents"]>;
|
|
14
|
+
getSession: () => Promise<SessionData | null>;
|
|
15
|
+
updateSession: (newData: SessionData) => ReturnType<SDK<URLHandlerParams>["updateSession"]>;
|
|
16
|
+
cleanupSession: () => ReturnType<SDK<URLHandlerParams>["cleanupSession"]>;
|
|
17
|
+
checkAuthentication: (params?: {
|
|
18
|
+
autoRefresh: boolean;
|
|
19
|
+
}) => ReturnType<SDK<URLHandlerParams>["checkAuthentication"]>;
|
|
20
|
+
init: () => ReturnType<SDK<URLHandlerParams>["init"]>;
|
|
21
|
+
tokenExchange: (params?: Parameters<SDK<URLHandlerParams>["tokenExchange"]>[0]) => ReturnType<SDK<URLHandlerParams>["tokenExchange"]>;
|
|
22
|
+
handleCallback: (url?: string | URL) => ReturnType<SDK<URLHandlerParams>["handleCallback"]>;
|
|
23
|
+
refresh: () => ReturnType<SDK<URLHandlerParams>["refresh"]>;
|
|
24
|
+
revoke: () => ReturnType<SDK<URLHandlerParams>["revoke"]>;
|
|
25
|
+
logout: (params?: Parameters<SDK<URLHandlerParams>["logout"]>[0]) => ReturnType<SDK<URLHandlerParams>["logout"]>;
|
|
26
|
+
};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{ConfigurationError as e,NetworkError as t,ProtocolError as n,ServerError as r}from"../utils/errors.mjs";import{isSessionExpired as i,loadSession as a,serializeSession as o}from"../utils/session.mjs";import{a as s,g as c,h as l,n as u,p as d,v as f}from"../assets/oidc.mjs";function p(p,m){let h={init:null,refresh:null,revoke:null,logout:null,tokenExchange:new Map},g={accessTokenExpired:new Set,init:new Set,loggedIn:new Set,sessionUpdated:new Set,sessionCleared:new Set,loginInitiated:new Set,flowInitiated:new Set,logoutInitiated:new Set,sessionLoaded:new Set,tokenRefreshed:new Set,tokenRefreshFailed:new Set,tokenRevoked:new Set,tokenRevokeFailed:new Set};function _(e,t){for(let n of g[e])n(...t)}function v(e,t){return g[e].add(t),{dispose:()=>g[e].delete(t)}}function y(e){for(let t in g)g[t].add(e);return{dispose:()=>{for(let t in g)g[t].delete(e)}}}async function b(){return await w(),p.session}async function x(e){await w(),e.id_token&&!e.claims&&(e.claims=await f({idToken:e.id_token,options:m})),m.serverSessionUri||await m.storage.set(m.storageTokenName,o(e)),p.session=e,_(`sessionUpdated`,[{idToken:p.session.id_token,accessToken:p.session.access_token,refreshToken:p.session.refresh_token,claims:p.session.claims}])}async function S(){await w(),m.serverSessionUri||await m.storage.delete(m.storageTokenName),p.session=null,_(`sessionCleared`,[])}async function C(e={autoRefresh:m.autoRefresh}){if(p.session?.access_token&&!i(p.session))return!0;if(e?.autoRefresh&&p.session?.refresh_token)try{await D()}catch{return!1}return!i(p.session)}async function w(){if(!p.initialized)return h.init||=(async()=>{try{if(!m.issuer){let t=new e(`Missing option: issuer`);throw m.logging?.error(`Required option missing`,t),t}if(!m.clientId){let t=new e(`Missing option: clientId`);throw m.logging?.error(`Required option missing`,t),t}if(!m.redirectUri){let t=new e(`Missing option: redirectUri`);throw m.logging?.error(`Required option missing`,t),t}if(m.scopes&&!Array.isArray(m.scopes)){let t=new e(`Invalid option: scopes`);throw m.logging?.error(`Invalid option provided`,t),t}m.serverSessionUri||(p.session=a(await m.storage.get(m.storageTokenName))),p.initialized=!0,_(`init`,[]),m.logging?.debug(`SDK initialized`),!p.session&&!m.serverSessionUri&&m.logging?.debug(`No session found in storage`),p.session?.access_token&&(_(`sessionLoaded`,[{idToken:p.session.id_token,accessToken:p.session.access_token,refreshToken:p.session.refresh_token,claims:p.session.claims}]),m.logging?.debug(`Session loaded from storage`)),p.session?.access_token&&i(p.session)&&(_(`accessTokenExpired`,[{accessToken:p.session.access_token,refreshToken:p.session.refresh_token}]),m.logging?.debug(`Access token has expired`))}finally{h.init=null}})(),h.init}async function T(e={}){await w();let t=e.state??``,r=h.tokenExchange.get(t);if(r)return r;let i=(async()=>{m.logging?.debug(`Exchanging authorization code for tokens`);try{let t=await s({params:e,options:m});if(!t.access_token)throw new n(`Missing access_token`);await x(t),m.logging?.debug(`Token exchange successful`),_(`loggedIn`,[{idToken:t.id_token,accessToken:t.access_token,refreshToken:t.refresh_token,claims:t.claims}]),m.logging&&(m.logging.xEventId=void 0,m.logging.info(`Login successful`))}catch(e){throw m.logging?.error(`Token exchange failed`,e),e}finally{h.tokenExchange.delete(t)}})();return h.tokenExchange.set(t,i),i}async function E(e){await w();let t=e??globalThis.window?.location.href;await T(await m.callbackHandler(t,m.responseMode))}async function D(){if(await w(),h.refresh)return h.refresh;if(h.revoke)try{await h.revoke}catch{}if(h.logout)try{await h.logout}catch{}if(m.logging?.debug(`Attempting to refresh session`),typeof p.session?.refresh_token!=`string`){m.logging?.debug(`Refresh called without refresh token`);return}return h.refresh=(async()=>{try{await x(await l({refreshToken:p.session.refresh_token,options:m,expectedSub:p.session?.claims?.sub})),_(`tokenRefreshed`,[{idToken:p.session?.id_token,accessToken:p.session?.access_token,refreshToken:p.session?.refresh_token,claims:p.session?.claims}]),m.logging?.debug(`Session refresh successful`)}catch(e){let n=p.session?.refresh_token;throw!(e instanceof t)&&!(e instanceof r)&&await S(),_(`tokenRefreshFailed`,[{refreshToken:n}]),m.logging?.error(`Session refresh failed`,e),e}finally{h.refresh=null}})(),h.refresh}async function O(){if(await w(),h.revoke)return h.revoke;if(h.refresh)try{await h.refresh}catch{}if(h.logout)try{await h.logout}catch{}return h.revoke=(async()=>{try{p.session?.refresh_token?m.logging?.debug(`Attempting to revoke refresh token`):p.session?.access_token&&m.logging?.debug(`Attempting to revoke access token`);let e=p.session;if(await S(),!e?.access_token&&!e?.refresh_token){m.logging?.debug(`Revoke called without session`);return}let t=e.refresh_token?`refresh_token`:`access_token`,n=t===`refresh_token`?e.refresh_token:e.access_token;try{await c({tokenTypeHint:t,token:n,options:m}),t===`refresh_token`?(_(`tokenRevoked`,[{token:e.refresh_token,tokenTypeHint:`refresh_token`}]),m.logging?.info(`Refresh token successfully revoked`)):(_(`tokenRevoked`,[{token:e.access_token,tokenTypeHint:`access_token`}]),m.logging?.info(`Access token successfully revoked`))}catch(n){throw t===`refresh_token`?_(`tokenRevokeFailed`,[{token:e.refresh_token,tokenTypeHint:`refresh_token`}]):_(`tokenRevokeFailed`,[{token:e.access_token,tokenTypeHint:`access_token`}]),m.logging?.error(`Token revocation failed`,n),n}}finally{h.revoke=null}})(),h.revoke}async function k(e){if(await w(),h.logout)return h.logout;if(h.revoke)try{await h.revoke}catch{}if(h.refresh)try{await h.refresh}catch{}return h.logout=(async()=>{try{m.logging?.debug(`Attempting to logout`);let t=p.session;if(await S(),_(`logoutInitiated`,[{idToken:t?.id_token,claims:t?.claims}]),m.logging?.debug(`Logout initiated`),!t?.id_token){m.logging?.debug(`Logout called without id token`);return}try{let n=await d(m),r=u({url:n.end_session_endpoint,idToken:t.id_token,postLogoutRedirectUri:e?.postLogoutRedirectUri});await m.urlHandler(r,e)}catch(e){m.logging?.error(`Unable to redirect to the end-session endpoint`,e)}}finally{h.logout=null}})(),h.logout}return{dispatchEvent:_,subscribeToEvent:v,subscribeToAllEvents:y,getSession:b,updateSession:x,cleanupSession:S,checkAuthentication:C,init:w,tokenExchange:T,handleCallback:E,refresh:D,revoke:O,logout:k}}export{p as createBaseFlow};
|
|
2
|
+
//# sourceMappingURL=base.mjs.map
|