@strivacity/sdk-core 4.0.0-beta.1 → 4.0.0-beta.2

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.
Files changed (98) hide show
  1. package/README.md +228 -87
  2. package/dist/assets/oidc.cjs +1 -1
  3. package/dist/assets/oidc.cjs.map +1 -1
  4. package/dist/assets/oidc.mjs +1 -1
  5. package/dist/assets/oidc.mjs.map +1 -1
  6. package/dist/assets/server.cjs +1 -1
  7. package/dist/assets/server.cjs.map +1 -1
  8. package/dist/assets/server.mjs +1 -1
  9. package/dist/assets/server.mjs.map +1 -1
  10. package/dist/flows/base.cjs +1 -1
  11. package/dist/flows/base.cjs.map +1 -1
  12. package/dist/flows/base.d.ts +4 -2
  13. package/dist/flows/base.mjs +1 -1
  14. package/dist/flows/base.mjs.map +1 -1
  15. package/dist/flows/popup.cjs +1 -1
  16. package/dist/flows/popup.cjs.map +1 -1
  17. package/dist/flows/popup.mjs +1 -1
  18. package/dist/flows/popup.mjs.map +1 -1
  19. package/dist/index.cjs +1 -1
  20. package/dist/index.cjs.map +1 -1
  21. package/dist/index.d.ts +6 -2
  22. package/dist/index.mjs +1 -1
  23. package/dist/index.mjs.map +1 -1
  24. package/dist/server/base.cjs +1 -1
  25. package/dist/server/base.cjs.map +1 -1
  26. package/dist/server/base.d.ts +2 -4
  27. package/dist/server/base.mjs +1 -1
  28. package/dist/server/base.mjs.map +1 -1
  29. package/dist/server/index.cjs +1 -1
  30. package/dist/server/index.mjs +1 -1
  31. package/dist/storages/cache.cjs.map +1 -1
  32. package/dist/storages/cache.d.ts +1 -1
  33. package/dist/storages/cache.mjs.map +1 -1
  34. package/dist/storages/index.cjs +1 -1
  35. package/dist/storages/index.mjs +1 -1
  36. package/dist/storages/server.cjs +1 -1
  37. package/dist/storages/server.d.ts +29 -1
  38. package/dist/storages/server.mjs +1 -1
  39. package/dist/storages/worker.cjs.map +1 -1
  40. package/dist/storages/worker.d.ts +1 -1
  41. package/dist/storages/worker.mjs.map +1 -1
  42. package/dist/types/native.d.ts +67 -2
  43. package/dist/types/oidc.cjs.map +1 -1
  44. package/dist/types/oidc.d.ts +41 -6
  45. package/dist/types/oidc.mjs.map +1 -1
  46. package/dist/types/popup.d.ts +1 -1
  47. package/dist/types/server.d.ts +21 -9
  48. package/dist/utils/index.cjs +1 -1
  49. package/dist/utils/index.d.ts +1 -0
  50. package/dist/utils/index.mjs +1 -1
  51. package/dist/utils/native-login.cjs +2 -0
  52. package/dist/utils/native-login.cjs.map +1 -0
  53. package/dist/utils/native-login.d.ts +13 -0
  54. package/dist/utils/native-login.mjs +2 -0
  55. package/dist/utils/native-login.mjs.map +1 -0
  56. package/dist/utils/oidc.d.ts +3 -4
  57. package/dist/utils/path.cjs +2 -0
  58. package/dist/utils/path.cjs.map +1 -0
  59. package/dist/utils/path.d.ts +16 -0
  60. package/dist/utils/path.mjs +2 -0
  61. package/dist/utils/path.mjs.map +1 -0
  62. package/dist/utils/server.d.ts +5 -4
  63. package/dist/utils/session.cjs +1 -1
  64. package/dist/utils/session.cjs.map +1 -1
  65. package/dist/utils/session.d.ts +9 -1
  66. package/dist/utils/session.mjs +1 -1
  67. package/dist/utils/session.mjs.map +1 -1
  68. package/package.json +1 -1
  69. package/testing/tests/flows/base.spec.ts +0 -1030
  70. package/testing/tests/flows/embedded.spec.ts +0 -443
  71. package/testing/tests/flows/index.spec.ts +0 -8
  72. package/testing/tests/flows/native.spec.ts +0 -487
  73. package/testing/tests/flows/popup.spec.ts +0 -400
  74. package/testing/tests/flows/redirect.spec.ts +0 -369
  75. package/testing/tests/handlers/embedded.spec.ts +0 -199
  76. package/testing/tests/handlers/index.spec.ts +0 -8
  77. package/testing/tests/handlers/native.spec.ts +0 -283
  78. package/testing/tests/handlers/popup.spec.ts +0 -206
  79. package/testing/tests/handlers/redirect.spec.ts +0 -70
  80. package/testing/tests/index.spec.ts +0 -78
  81. package/testing/tests/server/base.spec.ts +0 -846
  82. package/testing/tests/server/index.spec.ts +0 -15
  83. package/testing/tests/storages/cache.spec.ts +0 -107
  84. package/testing/tests/storages/index.spec.ts +0 -22
  85. package/testing/tests/storages/indexeddb.spec.ts +0 -113
  86. package/testing/tests/storages/local.spec.ts +0 -46
  87. package/testing/tests/storages/memory.spec.ts +0 -51
  88. package/testing/tests/storages/server.spec.ts +0 -435
  89. package/testing/tests/storages/session.spec.ts +0 -46
  90. package/testing/tests/storages/worker.spec.ts +0 -106
  91. package/testing/tests/utils/common.spec.ts +0 -77
  92. package/testing/tests/utils/credentials.spec.ts +0 -195
  93. package/testing/tests/utils/dom.spec.ts +0 -37
  94. package/testing/tests/utils/index.spec.ts +0 -71
  95. package/testing/tests/utils/logging.spec.ts +0 -82
  96. package/testing/tests/utils/oidc.spec.ts +0 -745
  97. package/testing/tests/utils/server.spec.ts +0 -235
  98. package/testing/tests/utils/session.spec.ts +0 -87
@@ -1,2 +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,refreshSkew:60,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.refreshSkew??=g.refreshSkew,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}});
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"),c=require("../utils/path.cjs");async function l(e={}){let t=x();return{id:C(16),createdAt:r.timestamp(),codeVerifier:t,metadata:e,codeChallenge:await S(t),nonce:C(16)}}function u(e){return JSON.parse(e)}function d(e){return JSON.stringify(e)}var f=0,p=null,m=null,h=new Map;function g(){return{initialized:!1,session:null,sessionId:null,shortAppId:null,language:globalThis.navigator?.language??`en-US`}}var _={lazyLoad:!1,autoRefresh:!0,refreshSkew:60,clockSkew:60,serverSessionUri:null,authUrlPrefix:`/auth`,scopes:[`openid`],responseType:`code`,responseMode:`query`,storageTokenName:`sty.session`,discoveryDocumentCacheTTL:3600,jwksCacheTTL:600};async function v(t){return m&&f>r.timestamp()?m:p||(p=(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 m=i,f=r.timestamp()+t.discoveryDocumentCacheTTL,i}finally{p=null}})(),p)}async function y({jwksUri:t,options:n,forceRefresh:i=!1}){let a=h.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 h.set(t,{keys:s.keys,expiresAt:r.timestamp()+n.jwksCacheTTL}),s}function b(e){let t={...e};return t.issuer=t.issuer.endsWith(`/`)?t.issuer.slice(0,-1):t.issuer,t.storage??=o.createLocalStorage(),t.stateStorage??=s.createSessionStorage(),t.httpClient??=n.createHttpClient(t.logging),t.urlHandler??=a.redirectUrlHandler,t.callbackHandler??=a.redirectCallbackHandler,t.lazyLoad??=_.lazyLoad,t.autoRefresh??=_.autoRefresh,t.refreshSkew??=_.refreshSkew,t.clockSkew??=_.clockSkew,t.serverSessionUri??=_.serverSessionUri,t.authUrlPrefix??=_.authUrlPrefix,t.scopes??=_.scopes,t.responseType??=_.responseType,t.responseMode??=_.responseMode,t.storageTokenName??=_.storageTokenName,t.discoveryDocumentCacheTTL??=_.discoveryDocumentCacheTTL,t.jwksCacheTTL??=_.jwksCacheTTL,t}function x(){let e=new Uint8Array(32);return globalThis.crypto.getRandomValues(e),t.encodeBase64URL(e.buffer)}async function S(e){let n=new TextEncoder().encode(e),r=await globalThis.crypto.subtle.digest(`SHA-256`,n);return t.encodeBase64URL(r)}function C(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 w(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 T({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 y({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 y({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 E(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 D({idToken:t,options:n,verifySignature:i=!1,expectedSub:a,expectedNonce:o}){let s=await v(n),c=i?await T({token:t,options:n,jwksUri:s.jwks_uri}):w(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+n.clockSkew<=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 O({url:e,includeOAuthParams:t=!0,persistState:n=!0,params:r,options:i}){let a=await l();if(a.metadata={},!e){let t=await v(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)}let o=c.toSameOriginPath(r.returnTo);return o&&t?a.metadata.returnTo=o:o&&e.searchParams.set(`returnTo`,o),n&&await i.stateStorage.set(`sty.${a.id}`,d(a)),e}function k({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 A({url:t,params:n,options:r}){let a=i.createSession(n),o=`sty.${a.state}`;if(a.error)throw await r.stateStorage.delete(o),new e.OidcError(a.error,a.error_description,a.error_uri);if(!a.code)throw new e.ProtocolError(`Invalid or missing authorization code`);let s=await r.stateStorage.get(o);if(!s)throw new e.ProtocolError(`Invalid or missing state`);let c;try{c=u(s)}catch{throw new e.ProtocolError(`Invalid or missing state`)}await r.stateStorage.delete(o);let l=await v(r),d=t??l.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 D({idToken:m.id_token,expectedNonce:c.nonce,options:r})),m}async function j({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 v(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 D({idToken:h.id_token,expectedSub:l,options:r})),h}async function M({url:t,tokenTypeHint:n,token:r,options:i,clientId:a}){let o=await v(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 N({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 P({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 F({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 d}}),Object.defineProperty(exports,"_",{enumerable:!0,get:function(){return F}}),Object.defineProperty(exports,"a",{enumerable:!0,get:function(){return A}}),Object.defineProperty(exports,"b",{enumerable:!0,get:function(){return l}}),Object.defineProperty(exports,"c",{enumerable:!0,get:function(){return S}}),Object.defineProperty(exports,"d",{enumerable:!0,get:function(){return C}}),Object.defineProperty(exports,"f",{enumerable:!0,get:function(){return g}}),Object.defineProperty(exports,"g",{enumerable:!0,get:function(){return M}}),Object.defineProperty(exports,"h",{enumerable:!0,get:function(){return j}}),Object.defineProperty(exports,"i",{enumerable:!0,get:function(){return _}}),Object.defineProperty(exports,"l",{enumerable:!0,get:function(){return x}}),Object.defineProperty(exports,"m",{enumerable:!0,get:function(){return b}}),Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return k}}),Object.defineProperty(exports,"o",{enumerable:!0,get:function(){return N}}),Object.defineProperty(exports,"p",{enumerable:!0,get:function(){return v}}),Object.defineProperty(exports,"r",{enumerable:!0,get:function(){return w}}),Object.defineProperty(exports,"s",{enumerable:!0,get:function(){return P}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return O}}),Object.defineProperty(exports,"u",{enumerable:!0,get:function(){return E}}),Object.defineProperty(exports,"v",{enumerable:!0,get:function(){return D}}),Object.defineProperty(exports,"x",{enumerable:!0,get:function(){return u}}),Object.defineProperty(exports,"y",{enumerable:!0,get:function(){return T}});
2
2
  //# sourceMappingURL=oidc.cjs.map
@@ -1 +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\trefreshSkew: 60,\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.refreshSkew ??= defaultOptions.refreshSkew;\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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"}
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';\nimport { toSameOriginPath } from './path.ts';\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\trefreshSkew: 60,\n\tclockSkew: 60,\n\tserverSessionUri: null,\n\tauthUrlPrefix: '/auth',\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} initOptions - 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>(initOptions: any): Options {\n\tconst options = { ...initOptions };\n\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.refreshSkew ??= defaultOptions.refreshSkew;\n\toptions.clockSkew ??= defaultOptions.clockSkew;\n\toptions.serverSessionUri ??= defaultOptions.serverSessionUri;\n\toptions.authUrlPrefix ??= defaultOptions.authUrlPrefix;\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` (allowing `clockSkew` seconds of tolerance), 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 + options.clockSkew <= 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\tconst returnTo = toSameOriginPath(params.returnTo);\n\n\tif (returnTo && includeOAuthParams) {\n\t\tstateData.metadata.returnTo = returnTo;\n\t} else if (returnTo) {\n\t\t// NOTE: server-managed login: the Server SDK login route keeps it and redirects there after its callback\n\t\turl.searchParams.set('returnTo', returnTo);\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\tconst stateKey = `sty.${session.state}`;\n\n\tif (session.error) {\n\t\tawait options.stateStorage.delete(stateKey);\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 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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"}
@@ -1,2 +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,refreshSkew:60,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.refreshSkew??=T.refreshSkew,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};
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";import{toSameOriginPath as _}from"../utils/path.mjs";async function v(e={}){let t=A();return{id:M(16),createdAt:d(),codeVerifier:t,metadata:e,codeChallenge:await j(t),nonce:M(16)}}function y(e){return JSON.parse(e)}function b(e){return JSON.stringify(e)}var x=0,S=null,C=null,w=new Map;function T(){return{initialized:!1,session:null,sessionId:null,shortAppId:null,language:globalThis.navigator?.language??`en-US`}}var E={lazyLoad:!1,autoRefresh:!0,refreshSkew:60,clockSkew:60,serverSessionUri:null,authUrlPrefix:`/auth`,scopes:[`openid`],responseType:`code`,responseMode:`query`,storageTokenName:`sty.session`,discoveryDocumentCacheTTL:3600,jwksCacheTTL:600};async function D(e){return C&&x>d()?C:S||(S=(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 C=n,x=d()+e.discoveryDocumentCacheTTL,n}finally{S=null}})(),S)}async function O({jwksUri:e,options:n,forceRefresh:r=!1}){let a=w.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 w.set(e,{keys:s.keys,expiresAt:d()+n.jwksCacheTTL}),s}function k(e){let t={...e};return t.issuer=t.issuer.endsWith(`/`)?t.issuer.slice(0,-1):t.issuer,t.storage??=h(),t.stateStorage??=g(),t.httpClient??=u(t.logging),t.urlHandler??=m,t.callbackHandler??=p,t.lazyLoad??=E.lazyLoad,t.autoRefresh??=E.autoRefresh,t.refreshSkew??=E.refreshSkew,t.clockSkew??=E.clockSkew,t.serverSessionUri??=E.serverSessionUri,t.authUrlPrefix??=E.authUrlPrefix,t.scopes??=E.scopes,t.responseType??=E.responseType,t.responseMode??=E.responseMode,t.storageTokenName??=E.storageTokenName,t.discoveryDocumentCacheTTL??=E.discoveryDocumentCacheTTL,t.jwksCacheTTL??=E.jwksCacheTTL,t}function A(){let e=new Uint8Array(32);return globalThis.crypto.getRandomValues(e),l(e.buffer)}async function j(e){let t=new TextEncoder().encode(e),n=await globalThis.crypto.subtle.digest(`SHA-256`,t);return l(n)}function M(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 N(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 P({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 O({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 O({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 F(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 I({idToken:e,options:t,verifySignature:n=!1,expectedSub:i,expectedNonce:a}){let o=await D(t),s=n?await P({token:e,options:t,jwksUri:o.jwks_uri}):N(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+t.clockSkew<=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 L({url:e,includeOAuthParams:t=!0,persistState:n=!0,params:r,options:i}){let a=await v();if(a.metadata={},!e){let t=await D(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)}let o=_(r.returnTo);return o&&t?a.metadata.returnTo=o:o&&e.searchParams.set(`returnTo`,o),n&&await i.stateStorage.set(`sty.${a.id}`,b(a)),e}function R({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 z({url:e,params:t,options:i}){let a=f(t),o=`sty.${a.state}`;if(a.error)throw await i.stateStorage.delete(o),new n(a.error,a.error_description,a.error_uri);if(!a.code)throw new r(`Invalid or missing authorization code`);let c=await i.stateStorage.get(o);if(!c)throw new r(`Invalid or missing state`);let l;try{l=y(c)}catch{throw new r(`Invalid or missing state`)}await i.stateStorage.delete(o);let u=await D(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 I({idToken:h.id_token,expectedNonce:l.nonce,options:i})),h}async function B({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 D(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 I({idToken:_.id_token,expectedSub:u,options:i})),_}async function V({url:e,tokenTypeHint:t,token:n,options:r,clientId:i}){let a=await D(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 H({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 U({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 W({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{b as S,W as _,z as a,v as b,j as c,M as d,T as f,V as g,B as h,E as i,A as l,k as m,R as n,H as o,D as p,N as r,U as s,L as t,F as u,I as v,y as x,P as y};
2
2
  //# sourceMappingURL=oidc.mjs.map
@@ -1 +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\trefreshSkew: 60,\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.refreshSkew ??= defaultOptions.refreshSkew;\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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"}
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';\nimport { toSameOriginPath } from './path.ts';\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\trefreshSkew: 60,\n\tclockSkew: 60,\n\tserverSessionUri: null,\n\tauthUrlPrefix: '/auth',\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} initOptions - 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>(initOptions: any): Options {\n\tconst options = { ...initOptions };\n\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.refreshSkew ??= defaultOptions.refreshSkew;\n\toptions.clockSkew ??= defaultOptions.clockSkew;\n\toptions.serverSessionUri ??= defaultOptions.serverSessionUri;\n\toptions.authUrlPrefix ??= defaultOptions.authUrlPrefix;\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` (allowing `clockSkew` seconds of tolerance), 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 + options.clockSkew <= 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\tconst returnTo = toSameOriginPath(params.returnTo);\n\n\tif (returnTo && includeOAuthParams) {\n\t\tstateData.metadata.returnTo = returnTo;\n\t} else if (returnTo) {\n\t\t// NOTE: server-managed login: the Server SDK login route keeps it and redirects there after its callback\n\t\turl.searchParams.set('returnTo', returnTo);\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\tconst stateKey = `sty.${session.state}`;\n\n\tif (session.error) {\n\t\tawait options.stateStorage.delete(stateKey);\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 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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"}