@imtbl/auth 2.12.5-alpha.21 → 2.12.5-alpha.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/index.js +27 -79
- package/dist/node/index.cjs +40 -96
- package/dist/node/index.js +27 -79
- package/dist/types/index.d.ts +1 -2
- package/dist/types/types.d.ts +1 -29
- package/package.json +6 -6
- package/src/Auth.test.ts +0 -225
- package/src/Auth.ts +2 -15
- package/src/index.ts +0 -15
- package/src/types.ts +0 -32
- package/README.md +0 -163
- package/dist/types/login/standalone.d.ts +0 -144
- package/src/login/standalone.ts +0 -748
package/dist/node/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { UserManager, User, ErrorTimeout, ErrorResponse, InMemoryWebStorage, WebStorageStateStore } from 'oidc-client-ts';
|
|
2
|
-
import
|
|
2
|
+
import Ce from 'localforage';
|
|
3
3
|
import { track, identify, getDetail, Detail, trackFlow, trackError } from '@imtbl/metrics';
|
|
4
4
|
|
|
5
|
-
var
|
|
5
|
+
var P=(a=>(a.AUTHENTICATION_ERROR="AUTHENTICATION_ERROR",a.INVALID_CONFIGURATION="INVALID_CONFIGURATION",a.WALLET_CONNECTION_ERROR="WALLET_CONNECTION_ERROR",a.NOT_LOGGED_IN_ERROR="NOT_LOGGED_IN_ERROR",a.SILENT_LOGIN_ERROR="SILENT_LOGIN_ERROR",a.REFRESH_TOKEN_ERROR="REFRESH_TOKEN_ERROR",a.USER_REGISTRATION_ERROR="USER_REGISTRATION_ERROR",a.USER_NOT_REGISTERED_ERROR="USER_NOT_REGISTERED_ERROR",a.LOGOUT_ERROR="LOGOUT_ERROR",a.TRANSFER_ERROR="TRANSFER_ERROR",a.CREATE_ORDER_ERROR="CREATE_ORDER_ERROR",a.CANCEL_ORDER_ERROR="CANCEL_ORDER_ERROR",a.EXCHANGE_TRANSFER_ERROR="EXCHANGE_TRANSFER_ERROR",a.CREATE_TRADE_ERROR="CREATE_TRADE_ERROR",a.OPERATION_NOT_SUPPORTED_ERROR="OPERATION_NOT_SUPPORTED_ERROR",a.LINK_WALLET_ALREADY_LINKED_ERROR="LINK_WALLET_ALREADY_LINKED_ERROR",a.LINK_WALLET_MAX_WALLETS_LINKED_ERROR="LINK_WALLET_MAX_WALLETS_LINKED_ERROR",a.LINK_WALLET_VALIDATION_ERROR="LINK_WALLET_VALIDATION_ERROR",a.LINK_WALLET_DUPLICATE_NONCE_ERROR="LINK_WALLET_DUPLICATE_NONCE_ERROR",a.LINK_WALLET_GENERIC_ERROR="LINK_WALLET_GENERIC_ERROR",a.SERVICE_UNAVAILABLE_ERROR="SERVICE_UNAVAILABLE_ERROR",a.TRANSACTION_REJECTED="TRANSACTION_REJECTED",a))(P||{});function U(n){return typeof n=="object"&&n!==null&&"code"in n&&"message"in n}var ee=n=>{if(U(n))return n;if(typeof n=="object"&&n!==null&&"response"in n){let{response:e}=n;if(e?.data&&U(e.data))return e.data}},p=class extends Error{type;constructor(e,t){super(e),this.type=t;}},g=async(n,e)=>{try{return await n()}catch(t){let r;if(t instanceof p&&t.type==="SERVICE_UNAVAILABLE_ERROR")throw new p(t.message,t.type);let i=ee(t);throw i?r=i.message:r=t.message,new p(r,e)}};var te=(n,e,t)=>{let r=e.map(i=>!n[i]&&i).filter(i=>i).join(", ");if(r!==""){let i=`${r} cannot be null`;throw new p(i,"INVALID_CONFIGURATION")}},y=class{authenticationDomain;passportDomain;oidcConfiguration;crossSdkBridgeEnabled;popupOverlayOptions;constructor({authenticationDomain:e,passportDomain:t,crossSdkBridgeEnabled:r,popupOverlayOptions:i,...o}){te(o,["clientId","redirectUri"]),this.oidcConfiguration=o,this.crossSdkBridgeEnabled=r||!1,this.popupOverlayOptions=i,this.authenticationDomain=e||"https://auth.immutable.com",this.passportDomain=t||"https://passport.immutable.com";}};var F=(e=>(e.ZKEVM="zkEvm",e))(F||{}),I=(t=>(t.ZKEVM="zkevm",t.ARBITRUM_ONE="arbitrum_one",t))(I||{}),x=n=>!!n.zkEvm,H=(r=>(r.OptedIn="opted_in",r.Unsubscribed="unsubscribed",r.Subscribed="subscribed",r))(H||{}),M=(t=>(t.LOGGED_OUT="loggedOut",t.LOGGED_IN="loggedIn",t))(M||{});var V="im_passport_embedded_login_prompt";var h="passport-overlay",R="passport-overlay-contents",A=`${h}-close`,w=`${h}-try-again`,G=`
|
|
6
6
|
<svg
|
|
7
7
|
viewBox="0 0 20 20"
|
|
8
8
|
fill="none"
|
|
@@ -14,7 +14,7 @@ var I=(p=>(p.AUTHENTICATION_ERROR="AUTHENTICATION_ERROR",p.INVALID_CONFIGURATION
|
|
|
14
14
|
fill="#F3F3F3"
|
|
15
15
|
/>
|
|
16
16
|
</svg>
|
|
17
|
-
`,
|
|
17
|
+
`,B=`
|
|
18
18
|
<svg
|
|
19
19
|
viewBox="0 0 17 16"
|
|
20
20
|
fill="none"
|
|
@@ -28,7 +28,7 @@ var I=(p=>(p.AUTHENTICATION_ERROR="AUTHENTICATION_ERROR",p.INVALID_CONFIGURATION
|
|
|
28
28
|
fill="#E01A3D"
|
|
29
29
|
/>
|
|
30
30
|
</svg>
|
|
31
|
-
`,
|
|
31
|
+
`,S=`
|
|
32
32
|
<svg
|
|
33
33
|
style="
|
|
34
34
|
max-width: 123px !important;
|
|
@@ -211,9 +211,9 @@ var I=(p=>(p.AUTHENTICATION_ERROR="AUTHENTICATION_ERROR",p.INVALID_CONFIGURATION
|
|
|
211
211
|
</clipPath>
|
|
212
212
|
</defs>
|
|
213
213
|
</svg>
|
|
214
|
-
`;var
|
|
214
|
+
`;var re=()=>`
|
|
215
215
|
<button
|
|
216
|
-
id="${
|
|
216
|
+
id="${A}"
|
|
217
217
|
style="
|
|
218
218
|
background: #f3f3f326 !important;
|
|
219
219
|
border: none !important;
|
|
@@ -229,11 +229,11 @@ var I=(p=>(p.AUTHENTICATION_ERROR="AUTHENTICATION_ERROR",p.INVALID_CONFIGURATION
|
|
|
229
229
|
justify-content: center !important;
|
|
230
230
|
"
|
|
231
231
|
>
|
|
232
|
-
${
|
|
232
|
+
${G}
|
|
233
233
|
</button>
|
|
234
|
-
`,
|
|
234
|
+
`,K=()=>`
|
|
235
235
|
<button
|
|
236
|
-
id="${
|
|
236
|
+
id="${w}"
|
|
237
237
|
style="
|
|
238
238
|
margin-top: 27px !important;
|
|
239
239
|
color: #f3f3f3 !important;
|
|
@@ -248,8 +248,8 @@ var I=(p=>(p.AUTHENTICATION_ERROR="AUTHENTICATION_ERROR",p.INVALID_CONFIGURATION
|
|
|
248
248
|
>
|
|
249
249
|
Try again
|
|
250
250
|
</button>
|
|
251
|
-
`,
|
|
252
|
-
${
|
|
251
|
+
`,ne=()=>`
|
|
252
|
+
${S}
|
|
253
253
|
<div
|
|
254
254
|
style="
|
|
255
255
|
color: #e01a3d !important;
|
|
@@ -259,7 +259,7 @@ var I=(p=>(p.AUTHENTICATION_ERROR="AUTHENTICATION_ERROR",p.INVALID_CONFIGURATION
|
|
|
259
259
|
margin-bottom: 10px !important;
|
|
260
260
|
"
|
|
261
261
|
>
|
|
262
|
-
${
|
|
262
|
+
${B}
|
|
263
263
|
Pop-up blocked
|
|
264
264
|
</div>
|
|
265
265
|
<p style="
|
|
@@ -272,9 +272,9 @@ var I=(p=>(p.AUTHENTICATION_ERROR="AUTHENTICATION_ERROR",p.INVALID_CONFIGURATION
|
|
|
272
272
|
If the problem continues, adjust your<br />
|
|
273
273
|
browser settings.
|
|
274
274
|
</p>
|
|
275
|
-
${
|
|
276
|
-
`,
|
|
277
|
-
${
|
|
275
|
+
${K()}
|
|
276
|
+
`,ie=()=>`
|
|
277
|
+
${S}
|
|
278
278
|
<p style="
|
|
279
279
|
color: #b6b6b6 !important;
|
|
280
280
|
text-align: center !important;
|
|
@@ -283,10 +283,10 @@ var I=(p=>(p.AUTHENTICATION_ERROR="AUTHENTICATION_ERROR",p.INVALID_CONFIGURATION
|
|
|
283
283
|
>
|
|
284
284
|
Secure pop-up not showing?<br />We'll help you re-launch
|
|
285
285
|
</p>
|
|
286
|
-
${
|
|
287
|
-
`,
|
|
286
|
+
${K()}
|
|
287
|
+
`,Z=n=>`
|
|
288
288
|
<div
|
|
289
|
-
id="${
|
|
289
|
+
id="${h}"
|
|
290
290
|
style="
|
|
291
291
|
position: fixed !important;
|
|
292
292
|
top: 0 !important;
|
|
@@ -309,9 +309,9 @@ var I=(p=>(p.AUTHENTICATION_ERROR="AUTHENTICATION_ERROR",p.INVALID_CONFIGURATION
|
|
|
309
309
|
z-index: 2147483647 !important;
|
|
310
310
|
"
|
|
311
311
|
>
|
|
312
|
-
${
|
|
312
|
+
${re()}
|
|
313
313
|
<div
|
|
314
|
-
id="${
|
|
314
|
+
id="${R}"
|
|
315
315
|
style="
|
|
316
316
|
display: flex !important;
|
|
317
317
|
flex-direction: column !important;
|
|
@@ -322,9 +322,9 @@ var I=(p=>(p.AUTHENTICATION_ERROR="AUTHENTICATION_ERROR",p.INVALID_CONFIGURATION
|
|
|
322
322
|
${n??""}
|
|
323
323
|
</div>
|
|
324
324
|
</div>
|
|
325
|
-
`,
|
|
325
|
+
`,W=()=>`
|
|
326
326
|
<div
|
|
327
|
-
id="${
|
|
327
|
+
id="${h}"
|
|
328
328
|
style="
|
|
329
329
|
position: fixed;
|
|
330
330
|
top: 0;
|
|
@@ -342,7 +342,7 @@ var I=(p=>(p.AUTHENTICATION_ERROR="AUTHENTICATION_ERROR",p.INVALID_CONFIGURATION
|
|
|
342
342
|
"
|
|
343
343
|
>
|
|
344
344
|
<div
|
|
345
|
-
id="${
|
|
345
|
+
id="${R}"
|
|
346
346
|
style="
|
|
347
347
|
display: flex;
|
|
348
348
|
flex-direction: column;
|
|
@@ -351,7 +351,7 @@ var I=(p=>(p.AUTHENTICATION_ERROR="AUTHENTICATION_ERROR",p.INVALID_CONFIGURATION
|
|
|
351
351
|
"
|
|
352
352
|
/>
|
|
353
353
|
</div>
|
|
354
|
-
`;function
|
|
354
|
+
`;function k({id:n,href:e,rel:t,crossOrigin:r}){let i=`${h}-${n}`;if(!document.getElementById(i)){let o=document.createElement("link");o.id=i,o.href=e,t&&(o.rel=t),r&&(o.crossOrigin=r),document.head.appendChild(o);}}var $=()=>Z(ne()),z=()=>Z(ie());var u=class{static overlay;static onCloseListener;static closeButton;static remove(){this.onCloseListener&&this.closeButton?.removeEventListener?.("click",this.onCloseListener),this.overlay?.remove(),this.closeButton=void 0,this.onCloseListener=void 0,this.overlay=void 0;}static appendOverlay(e,t){if(!this.overlay){let r=document.createElement("div");r.innerHTML=W(),document.body.insertAdjacentElement("beforeend",r);let i=document.querySelector(`#${R}`);i&&i.appendChild(e),r.addEventListener("click",t),this.overlay=r;}}};var ae=660,de=440,le="16px",Y="passport-embedded-login-keyframes",J="passport-embedded-login-iframe",v=class n{config;constructor(e){this.config=e;}getHref=()=>`${this.config.authenticationDomain}/im-embedded-login-prompt?client_id=${this.config.oidcConfiguration.clientId}&rid=${getDetail(Detail.RUNTIME_ID)}`;static appendIFrameStylesIfNeeded=()=>{if(document.getElementById(Y))return;let e=document.createElement("style");e.id=Y,e.textContent=`
|
|
355
355
|
@keyframes passportEmbeddedLoginPromptPopBounceIn {
|
|
356
356
|
0% {
|
|
357
357
|
opacity: 0.5;
|
|
@@ -370,7 +370,7 @@ var I=(p=>(p.AUTHENTICATION_ERROR="AUTHENTICATION_ERROR",p.INVALID_CONFIGURATION
|
|
|
370
370
|
}
|
|
371
371
|
|
|
372
372
|
@media (max-height: 400px) {
|
|
373
|
-
#${
|
|
373
|
+
#${J} {
|
|
374
374
|
width: 100% !important;
|
|
375
375
|
max-width: none !important;
|
|
376
376
|
}
|
|
@@ -384,58 +384,6 @@ var I=(p=>(p.AUTHENTICATION_ERROR="AUTHENTICATION_ERROR",p.INVALID_CONFIGURATION
|
|
|
384
384
|
opacity: 1;
|
|
385
385
|
}
|
|
386
386
|
}
|
|
387
|
-
`,document.head.appendChild(e);};getEmbeddedLoginIFrame=()=>{let e=document.createElement("iframe");return e.id=ie,e.src=this.getHref(),e.style.height="100vh",e.style.width="100vw",e.style.maxHeight=`${ke}px`,e.style.maxWidth=`${Ie}px`,e.style.borderRadius=Ae,e.style.opacity="0",e.style.transform="scale(0.6)",e.style.animation="passportEmbeddedLoginPromptPopBounceIn 1s ease forwards",n.appendIFrameStylesIfNeeded(),e};displayEmbeddedLoginPrompt(){return new Promise((e,t)=>{let r=this.getEmbeddedLoginIFrame(),o=({data:i,origin:s})=>{if(!(s!==this.config.authenticationDomain||i.eventType!==Q))switch(i.messageType){case"login_method_selected":{let a=i.payload;window.removeEventListener("message",o),h.remove(),e(a);break}case"login_prompt_error":{window.removeEventListener("message",o),h.remove(),t(new Error("Error during embedded login prompt",{cause:i.payload}));break}case"login_prompt_closed":{window.removeEventListener("message",o),h.remove(),t(new Error("Popup closed by user"));break}default:window.removeEventListener("message",o),h.remove(),t(new Error(`Unsupported message type: ${i.messageType}`));break}};window.addEventListener("message",o),h.appendOverlay(r,()=>{window.removeEventListener("message",o),h.remove(),t(new Error("Popup closed by user"));});})}};var R=class{listeners=new Map;emit(e,...t){let r=this.listeners.get(e);!r||r.size===0||[...r].forEach(o=>{o(...t);});}on(e,t){let r=this.listeners.get(e)??new Set;r.add(t),this.listeners.set(e,r);}removeListener(e,t){let r=this.listeners.get(e);r&&(r.delete(t),r.size===0&&this.listeners.delete(e));}};var m=async(n,e,t=!0,r=!0)=>{let o=trackFlow("passport",e,t);try{return await n(o)}catch(i){throw i instanceof Error?trackError("passport",e,i,{flowId:o.details.flowId}):o.addEvent("errored"),i}finally{r&&o.addEvent("End");}};var Se=()=>typeof globalThis<"u"?globalThis:typeof self<"u"?self:typeof window<"u"?window:typeof global<"u"?global:{},xe=n=>{let e=n.replace(/-/g,"+").replace(/_/g,"/"),t=e.length%4===0?"":"=".repeat(4-e.length%4);return e+t},De=n=>{let e=Se();if(typeof e.atob!="function")return null;let t=e.atob(n),r=new Uint8Array(t.length);for(let i=0;i<t.length;i+=1)r[i]=t.charCodeAt(i);if(typeof e.TextDecoder=="function")return new e.TextDecoder("utf-8").decode(r);let o="";for(let i=0;i<r.length;i+=1)o+=String.fromCharCode(r[i]);return o},Me=n=>{if(typeof Buffer<"u")return Buffer.from(n,"base64").toString("utf-8");let e=De(n);if(e===null)throw new Error("Base64 decoding is not supported in this environment");return e},u=n=>{if(typeof n!="string")throw new Error("JWT must be a string");let e=n.split(".");if(e.length<2)throw new Error("Invalid JWT: payload segment is missing");let t=e[1],r=Me(xe(t));try{return JSON.parse(r)}catch{throw new Error("Invalid JWT payload: unable to parse JSON")}};var se="pkce_state",ae="pkce_verifier",Ne=3600,L=class{isTokenValid(e){try{let r=u(e).exp??0,o=Date.now()/1e3+Ne;return r>o}catch{return !1}}savePKCEData(e){localStorage.setItem(se,e.state),localStorage.setItem(ae,e.verifier);}getPKCEData(){let e=localStorage.getItem(se),t=localStorage.getItem(ae);return e&&t?{state:e,verifier:t}:null}};var He=(...n)=>{if(typeof process>"u")return;process?.env?.JEST_WORKER_ID===void 0&&console.warn(...n);},v={warn:He};function de(n){try{let e=u(n),t=Math.floor(Date.now()/1e3);return e.exp?e.exp<=t+30:!0}catch{return !0}}function le(n){let{id_token:e,access_token:t}=n;return !t||!e?!0:de(t)||de(e)}var P=class{disableGenericPopupOverlay;disableBlockedPopupOverlay;overlay;isBlockedOverlay;tryAgainListener;onCloseListener;constructor(e,t=!1){this.disableBlockedPopupOverlay=e.disableBlockedPopupOverlay||!1,this.disableGenericPopupOverlay=e.disableGenericPopupOverlay||!1,this.isBlockedOverlay=t;}append(e,t){this.shouldAppendOverlay()&&(this.appendOverlay(),this.updateTryAgainButton(e),this.updateCloseButton(t));}update(e){this.updateTryAgainButton(e);}remove(){this.overlay&&this.overlay.remove();}shouldAppendOverlay(){return !(this.disableGenericPopupOverlay&&this.disableBlockedPopupOverlay||this.disableGenericPopupOverlay&&!this.isBlockedOverlay||this.disableBlockedPopupOverlay&&this.isBlockedOverlay)}appendOverlay(){if(!this.overlay){S({id:"link-googleapis",href:"https://fonts.googleapis.com"}),S({id:"link-gstatic",href:"https://fonts.gstatic.com",crossOrigin:"anonymous"}),S({id:"link-roboto",href:"https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,400;0,500;0,700;1,400;1,500;1,700&display=swap",rel:"stylesheet"});let t=document.createElement("div");t.innerHTML=this.isBlockedOverlay?re():ne(),document.body.insertAdjacentElement("beforeend",t),this.overlay=t;}}updateTryAgainButton(e){let t=document.getElementById(U);t&&(this.tryAgainListener&&t.removeEventListener("click",this.tryAgainListener),this.tryAgainListener=e,t.addEventListener("click",e));}updateCloseButton(e){let t=document.getElementById(b);t&&(this.onCloseListener&&t.removeEventListener("click",this.onCloseListener),this.onCloseListener=e,t.addEventListener("click",e));}};var x=class{storage;constructor(e,t){this.storage=Fe.createInstance({name:e,driver:t});}get length(){return this.storage.length()}clear(){return this.storage.clear()}getItem(e){return this.storage.getItem(e)}key(e){return this.storage.key(e)}async removeItem(e){await this.storage.removeItem(e);}async setItem(e,t){await this.storage.setItem(e,t);}};var Xe={"Content-Type":"application/x-www-form-urlencoded"},je=n=>{if(n)try{return JSON.parse(n)}catch{return}},et=(n,e,t)=>{if(n&&typeof n=="object"){let r=n,o=r.error_description??r.message??r.error;if(typeof o=="string"&&o.trim().length>0)return o}return e.trim().length>0?e:`Token request failed with status ${t}`},tt="/v2/logout",rt="/im-logged-out",nt="/authorize",ot=n=>n?rt:tt,it=n=>{let{authenticationDomain:e,oidcConfiguration:t}=n,r;n.crossSdkBridgeEnabled?r=new x("ImmutableSDKPassport",Fe.INDEXEDDB):typeof window<"u"?r=window.localStorage:r=new InMemoryWebStorage;let o=new WebStorageStateStore({store:r}),i=new URL(ot(n.crossSdkBridgeEnabled),e.replace(/^(?:https?:\/\/)?(.*)/,"https://$1"));return i.searchParams.set("client_id",t.clientId),t.logoutRedirectUri&&i.searchParams.set("returnTo",t.logoutRedirectUri),{authority:e,redirect_uri:t.redirectUri,popup_redirect_uri:t.popupRedirectUri||t.redirectUri,client_id:t.clientId,metadata:{authorization_endpoint:`${e}/authorize`,token_endpoint:`${e}/oauth/token`,userinfo_endpoint:`${e}/userinfo`,end_session_endpoint:i.toString(),revocation_endpoint:`${e}/oauth/revoke`},automaticSilentRenew:!1,scope:t.scope,userStore:o,revokeTokenTypes:["refresh_token"],extraQueryParams:{...t.audience?{audience:t.audience}:{}}}};function B(n){return btoa(String.fromCharCode(...new Uint8Array(n))).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}async function st(n){let t=new TextEncoder().encode(n);return window.crypto.subtle.digest("SHA-256",t)}var K=class n{config;userManager;deviceCredentialsManager;embeddedLoginPrompt;logoutMode;refreshingPromise=null;eventEmitter;constructor(e){this.config=new T(e),this.embeddedLoginPrompt=new O(this.config),this.userManager=new UserManager(it(this.config)),this.deviceCredentialsManager=new L,this.logoutMode=this.config.oidcConfiguration.logoutMode||"redirect",this.eventEmitter=new R,track("passport","initialise");}async login(e){return m(async()=>{let{useCachedSession:t=!1,useSilentLogin:r}=e||{},o=null;try{o=await this.getUserInternal();}catch(i){if(i instanceof Error&&!i.message.includes("Unknown or invalid refresh token")&&trackError("passport","login",i),t)throw i;v.warn("Failed to retrieve a cached user session",i);}if(!o&&r)o=await this.forceUserRefreshInternal();else if(!o&&!t){if(e?.useRedirectFlow)return await this.loginWithRedirectInternal(e?.directLoginOptions),null;o=await this.loginWithPopup(e?.directLoginOptions);}return o&&this.handleSuccessfulLogin(o),o},"login")}async loginWithRedirect(e){await this.loginWithRedirectInternal(e);}async loginCallback(){return m(async()=>{let e=await this.loginCallbackInternal();return e&&this.handleSuccessfulLogin(e),e},"loginCallback")}async logout(){await m(async()=>{await this.logoutInternal(),this.eventEmitter.emit("loggedOut");},"logout");}async getUser(){return this.getUserInternal()}async getUserOrLogin(){let e=null;try{e=await this.getUserInternal();}catch(r){v.warn("Failed to retrieve a cached user session",r);}if(e)return e;let t=await this.loginWithPopup();return this.handleSuccessfulLogin(t),t}async getUserZkEvm(){return this.getUserZkEvmInternal()}async getIdToken(){return m(async()=>(await this.getUserInternal())?.idToken,"getIdToken",!1)}async getAccessToken(){return m(async()=>(await this.getUserInternal())?.accessToken,"getAccessToken",!1,!1)}async isLoggedIn(){return await this.getUser()!==null}async forceUserRefresh(){return this.forceUserRefreshInternal()}forceUserRefreshInBackground(){this.forceUserRefreshInBackgroundInternal();}async loginWithPKCEFlow(e,t){return m(async()=>this.getPKCEAuthorizationUrl(e,t),"loginWithPKCEFlow")}async loginWithPKCEFlowCallback(e,t){return m(async()=>{let r=await this.loginWithPKCEFlowCallbackInternal(e,t);return this.handleSuccessfulLogin(r),r},"loginWithPKCEFlowCallback")}async storeTokens(e){return m(async()=>{let t=await this.storeTokensInternal(e);return this.handleSuccessfulLogin(t),t},"storeTokens")}async getLogoutUrl(){return m(async()=>(await this.userManager.removeUser(),this.eventEmitter.emit("loggedOut"),await this.getLogoutUrlInternal()||void 0),"getLogoutUrl")}async logoutSilentCallback(e){return m(()=>this.userManager.signoutSilentCallback(e),"logoutSilentCallback")}getConfig(){return this.config}async getClientId(){return this.config.oidcConfiguration.clientId}handleSuccessfulLogin(e){this.eventEmitter.emit("loggedIn",e),identify({passportId:e.profile.sub});}buildExtraQueryParams(e,t){let r={...this.userManager.settings?.extraQueryParams??{},rid:getDetail(Detail.RUNTIME_ID)||""};if(e){if(e.directLoginMethod==="email"){let o=e.email;o&&(r.direct=e.directLoginMethod,r.email=o);}else r.direct=e.directLoginMethod;e.marketingConsentStatus&&(r.marketingConsent=e.marketingConsentStatus);}return t&&(r.im_passport_trace_id=t),r}async loginWithRedirectInternal(e){await this.userManager.clearStaleState(),await E(async()=>{let t=this.buildExtraQueryParams(e);await this.userManager.signinRedirect({extraQueryParams:t});},"AUTHENTICATION_ERROR");}async loginWithPopup(e){return E(async()=>{let t,r;if(e)t=e;else if(!this.config.popupOverlayOptions?.disableHeadlessLoginPromptOverlay){let{imPassportTraceId:s,...a}=await this.embeddedLoginPrompt.displayEmbeddedLoginPrompt();t=a,r=s;}let o=window.crypto.randomUUID(),i=async()=>{let s=this.buildExtraQueryParams(t,r);return this.userManager.signinPopup({extraQueryParams:s,popupWindowFeatures:{width:410,height:450},popupWindowTarget:o,popupAbortOnClose:!0})};return new Promise((s,a)=>{i().then(l=>s(n.mapOidcUserToDomainModel(l))).catch(l=>{if(!(l instanceof Error)||l.message!=="Attempted to navigate on a disposed window"){a(l);return}let c=!1,d=new P(this.config.popupOverlayOptions||{},!0);d.append(async()=>{try{if(c)window.open("",o);else {c=!0;let g=await i();d.remove(),s(n.mapOidcUserToDomainModel(g));}}catch(g){d.remove(),a(g);}},()=>{d.remove(),a(new Error("Popup closed by user"));});});})},"AUTHENTICATION_ERROR")}static mapOidcUserToDomainModel=e=>{let t,r;if(e.id_token){let s=u(e.id_token);t=s?.passport,s?.username&&(r=s?.username);}let o={expired:e.expired,idToken:e.id_token,accessToken:e.access_token,refreshToken:e.refresh_token,profile:{sub:e.profile.sub,email:e.profile.email,nickname:e.profile.nickname,username:r}};t?.zkevm_eth_address&&t?.zkevm_user_admin_address&&(o.zkEvm={ethAddress:t.zkevm_eth_address,userAdminAddress:t.zkevm_user_admin_address});let i=Object.values(A).filter(s=>s!=="zkevm");for(let s of i){let a=t?.[s];a?.eth_address&&a?.user_admin_address&&(o[s]={ethAddress:a.eth_address,userAdminAddress:a.user_admin_address});}return o};static mapDeviceTokenResponseToOidcUser=e=>{let t=u(e.id_token);return new User({id_token:e.id_token,access_token:e.access_token,refresh_token:e.refresh_token,token_type:e.token_type,profile:{sub:t.sub,iss:t.iss,aud:t.aud,exp:t.exp,iat:t.iat,email:t.email,nickname:t.nickname,passport:t.passport,...t.username?{username:t.username}:{}}})};async loginCallbackInternal(){return E(async()=>{let e=await this.userManager.signinCallback();if(e)return n.mapOidcUserToDomainModel(e)},"AUTHENTICATION_ERROR")}async getPKCEAuthorizationUrl(e,t){let r=B(window.crypto.getRandomValues(new Uint8Array(32))),o=B(await st(r)),i=B(window.crypto.getRandomValues(new Uint8Array(32))),{redirectUri:s,scope:a,audience:l,clientId:c}=this.config.oidcConfiguration;this.deviceCredentialsManager.savePKCEData({state:i,verifier:r});let d=new URL(nt,this.config.authenticationDomain);if(d.searchParams.set("response_type","code"),d.searchParams.set("code_challenge",o),d.searchParams.set("code_challenge_method","S256"),d.searchParams.set("client_id",c),d.searchParams.set("redirect_uri",s),d.searchParams.set("state",i),a&&d.searchParams.set("scope",a),l&&d.searchParams.set("audience",l),e){if(e.directLoginMethod==="email"){let g=e.email;g&&(d.searchParams.set("direct",e.directLoginMethod),d.searchParams.set("email",g));}else d.searchParams.set("direct",e.directLoginMethod);e.marketingConsentStatus&&d.searchParams.set("marketingConsent",e.marketingConsentStatus);}return t&&d.searchParams.set("im_passport_trace_id",t),d.toString()}async loginWithPKCEFlowCallbackInternal(e,t){return E(async()=>{let r=this.deviceCredentialsManager.getPKCEData();if(!r)throw new Error("No code verifier or state for PKCE");if(t!==r.state)throw new Error("Provided state does not match stored state");let o=await this.getPKCEToken(e,r.verifier),i=n.mapDeviceTokenResponseToOidcUser(o),s=n.mapOidcUserToDomainModel(i);return await this.userManager.storeUser(i),s},"AUTHENTICATION_ERROR")}async getPKCEToken(e,t){let r=await fetch(`${this.config.authenticationDomain}/oauth/token`,{method:"POST",headers:Xe,body:new URLSearchParams({client_id:this.config.oidcConfiguration.clientId,grant_type:"authorization_code",code_verifier:t,code:e,redirect_uri:this.config.oidcConfiguration.redirectUri})}),o=await r.text(),i=je(o);if(!r.ok)throw new Error(et(i,o,r.status));if(!i||typeof i!="object")throw new Error("Token endpoint returned an invalid response");return i}async storeTokensInternal(e){return E(async()=>{let t=n.mapDeviceTokenResponseToOidcUser(e),r=n.mapOidcUserToDomainModel(t);return await this.userManager.storeUser(t),r},"AUTHENTICATION_ERROR")}async logoutInternal(){await E(async()=>{await this.userManager.revokeTokens(["refresh_token"]),this.logoutMode==="silent"?await this.userManager.signoutSilent():await this.userManager.signoutRedirect();},"LOGOUT_ERROR");}async getLogoutUrlInternal(){let e=this.userManager.settings?.metadata?.end_session_endpoint;return e||(v.warn("Failed to get logout URL"),null)}forceUserRefreshInBackgroundInternal(){this.refreshTokenAndUpdatePromise().catch(e=>{v.warn("Failed to refresh user token",e);});}async forceUserRefreshInternal(){return this.refreshTokenAndUpdatePromise().catch(e=>(v.warn("Failed to refresh user token",e),null))}async refreshTokenAndUpdatePromise(){return this.refreshingPromise?this.refreshingPromise:(this.refreshingPromise=new Promise((e,t)=>{(async()=>{try{let r=await this.userManager.signinSilent();if(r){let o=n.mapOidcUserToDomainModel(r);this.eventEmitter.emit("tokenRefreshed",o),e(o);return}e(null);}catch(r){let o="AUTHENTICATION_ERROR",i="Failed to refresh token",s=!0;if(r instanceof ErrorTimeout?(o="SILENT_LOGIN_ERROR",i=`${i}: ${r.message}`,s=!1):r instanceof ErrorResponse?(o="NOT_LOGGED_IN_ERROR",i=`${i}: ${r.message||r.error_description}`):r instanceof Error?i=`${i}: ${r.message}`:typeof r=="string"&&(i=`${i}: ${r}`),s){this.eventEmitter.emit("userRemoved",{reason:"refresh_failed",error:i});try{await this.userManager.removeUser();}catch(a){a instanceof Error&&(i=`${i}: Failed to remove user: ${a.message}`);}}t(new f(i,o));}finally{this.refreshingPromise=null;}})();}),this.refreshingPromise)}async getUserInternal(e=t=>!0){if(this.refreshingPromise){let r=await this.refreshingPromise;return r&&e(r)?r:null}let t=await this.userManager.getUser();if(!t)return null;if(!le(t)){let r=n.mapOidcUserToDomainModel(t);if(r&&e(r))return r}if(t.refresh_token){let r=await this.refreshTokenAndUpdatePromise();if(r&&e(r))return r}return null}async getUserZkEvmInternal(){let e=await this.getUserInternal(F);if(!e)throw new Error("Failed to obtain a User with the required ZkEvm attributes");return e}};var lt="im_passport_embedded_login_prompt",me="passport-embedded-login-iframe",ue="passport-overlay";var ct="https://auth.immutable.com",pt="platform_api",mt="openid profile email offline_access transact",ut="/authorize",gt="/oauth/token",Z="imtbl_pkce_data";function ge(n){return btoa(String.fromCharCode(...new Uint8Array(n))).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}async function ft(n){let t=new TextEncoder().encode(n);return window.crypto.subtle.digest("SHA-256",t)}function ce(){return ge(window.crypto.getRandomValues(new Uint8Array(32)))}function W(n){return n.authenticationDomain||ct}function ht(n){try{let e=u(n);if(e.exp)return e.exp*1e3}catch{}return Date.now()+3600*1e3}function Et(n){let{access_token:e,refresh_token:t,id_token:r}=n,o={sub:""},i;if(r)try{let{sub:s,email:a,nickname:l,passport:c}=u(r);o={sub:s,email:a,nickname:l},c?.zkevm_eth_address&&c?.zkevm_user_admin_address&&(i={ethAddress:c.zkevm_eth_address,userAdminAddress:c.zkevm_user_admin_address});}catch{}return {accessToken:e,refreshToken:t,idToken:r,accessTokenExpires:ht(e),profile:o,zkEvm:i}}function _t(n){typeof window<"u"&&window.sessionStorage&&window.sessionStorage.setItem(Z,JSON.stringify(n));}function yt(){if(typeof window<"u"&&window.sessionStorage){let n=window.sessionStorage.getItem(Z);if(n)try{return JSON.parse(n)}catch{return null}}return null}function pe(){typeof window<"u"&&window.sessionStorage&&window.sessionStorage.removeItem(Z);}function Ct(){let n="passport-embedded-login-keyframes";if(document.getElementById(n))return;let e=document.createElement("style");e.id=n,e.textContent=`
|
|
388
|
-
@keyframes passportEmbeddedLoginPromptPopBounceIn {
|
|
389
|
-
0% {
|
|
390
|
-
opacity: 0.5;
|
|
391
|
-
}
|
|
392
|
-
50% {
|
|
393
|
-
opacity: 1;
|
|
394
|
-
transform: scale(1.05);
|
|
395
|
-
}
|
|
396
|
-
75% {
|
|
397
|
-
transform: scale(0.98);
|
|
398
|
-
}
|
|
399
|
-
100% {
|
|
400
|
-
opacity: 1;
|
|
401
|
-
transform: scale(1);
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
@media (max-height: 400px) {
|
|
406
|
-
#${me} {
|
|
407
|
-
width: 100% !important;
|
|
408
|
-
max-width: none !important;
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
@keyframes passportEmbeddedLoginPromptOverlayFadeIn {
|
|
413
|
-
from {
|
|
414
|
-
opacity: 0;
|
|
415
|
-
}
|
|
416
|
-
to {
|
|
417
|
-
opacity: 1;
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
`,document.head.appendChild(e);}function Rt(n,e){let t=getDetail(Detail.RUNTIME_ID),r=document.createElement("iframe");return r.id=me,r.src=`${n}/im-embedded-login-prompt?client_id=${e}&rid=${t}`,r.style.height="100vh",r.style.width="100vw",r.style.maxHeight="660px",r.style.maxWidth="440px",r.style.borderRadius="16px",r.style.border="none",r.style.opacity="0",r.style.transform="scale(0.6)",r.style.animation="passportEmbeddedLoginPromptPopBounceIn 1s ease forwards",Ct(),r}function vt(){let n=document.createElement("div");n.id=ue,n.style.cssText=`
|
|
421
|
-
position: fixed;
|
|
422
|
-
top: 0;
|
|
423
|
-
left: 0;
|
|
424
|
-
width: 100%;
|
|
425
|
-
height: 100%;
|
|
426
|
-
display: flex;
|
|
427
|
-
flex-direction: column;
|
|
428
|
-
justify-content: center;
|
|
429
|
-
align-items: center;
|
|
430
|
-
z-index: 2147483647;
|
|
431
|
-
background: rgba(247, 247, 247, 0.24);
|
|
432
|
-
animation-name: passportEmbeddedLoginPromptOverlayFadeIn;
|
|
433
|
-
animation-duration: 0.8s;
|
|
434
|
-
`;let e=document.createElement("div");return e.id=_,e.style.cssText=`
|
|
435
|
-
display: flex;
|
|
436
|
-
flex-direction: column;
|
|
437
|
-
align-items: center;
|
|
438
|
-
width: 100%;
|
|
439
|
-
`,n.appendChild(e),n}function w(){document.getElementById(ue)?.remove();}function Tt(n,e){return new Promise((t,r)=>{let o=Rt(n,e),i=vt(),s=({data:c,origin:d})=>{if(!(d!==n||c.eventType!==lt))switch(c.messageType){case"login_method_selected":{let g=c.payload;window.removeEventListener("message",s),w(),t(g);break}case"login_prompt_error":{window.removeEventListener("message",s),w(),r(new Error("Error during embedded login prompt",{cause:c.payload}));break}case"login_prompt_closed":{window.removeEventListener("message",s),w(),r(new Error("Login closed by user"));break}default:window.removeEventListener("message",s),w(),r(new Error(`Unsupported message type: ${c.messageType}`));break}},a=c=>{c.target===i&&(window.removeEventListener("message",s),i.removeEventListener("click",a),w(),r(new Error("Login closed by user")));};window.addEventListener("message",s),i.addEventListener("click",a);let l=i.querySelector(`#${_}`);l&&l.appendChild(o),document.body.appendChild(i);})}async function fe(n,e){let t=W(n),r=ce(),o=ge(await ft(r)),i=ce(),s=new URL(ut,t);s.searchParams.set("response_type","code"),s.searchParams.set("code_challenge",o),s.searchParams.set("code_challenge_method","S256"),s.searchParams.set("client_id",n.clientId),s.searchParams.set("redirect_uri",n.redirectUri),s.searchParams.set("state",i),s.searchParams.set("scope",n.scope||mt),n.audience?s.searchParams.set("audience",n.audience):s.searchParams.set("audience",pt);let a=e?.directLoginOptions;return a&&(a.directLoginMethod==="email"?a.email&&(s.searchParams.set("direct","email"),s.searchParams.set("email",a.email)):s.searchParams.set("direct",a.directLoginMethod),a.marketingConsentStatus&&s.searchParams.set("marketingConsent",a.marketingConsentStatus)),{url:s.toString(),verifier:r,state:i}}async function he(n,e,t,r){let i=`${W(n)}${gt}`,s=await fetch(i,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({grant_type:"authorization_code",client_id:n.clientId,code_verifier:t,code:e,redirect_uri:r})});if(!s.ok){let l=await s.text(),c=`Token exchange failed with status ${s.status}`;try{let d=JSON.parse(l);d.error_description?c=d.error_description:d.error&&(c=d.error);}catch{l&&(c=l);}throw new Error(c)}let a=await s.json();return Et(a)}async function Ee(n,e){track("passport","standaloneLoginWithPopup");let t=n.popupRedirectUri||n.redirectUri,r={...n,redirectUri:t},{url:o,verifier:i,state:s}=await fe(r,e);return new Promise((a,l)=>{let g=window.screenX+(window.outerWidth-500)/2,_e=window.screenY+(window.outerHeight-600)/2,y=window.open(o,"immutable_login",`width=500,height=600,left=${g},top=${_e},toolbar=no,menubar=no`);if(!y){l(new Error("Popup was blocked. Please allow popups for this site."));return}let M=setInterval(()=>{try{if(y.closed){clearInterval(M),l(new Error("Login popup was closed"));return}let N=y.location.href;if(N&&N.startsWith(t)){clearInterval(M),y.close();let k=new URL(N),$=k.searchParams.get("code"),ye=k.searchParams.get("state"),z=k.searchParams.get("error"),Ce=k.searchParams.get("error_description");if(z){l(new Error(Ce||z));return}if(!$){l(new Error("No authorization code received"));return}if(ye!==s){l(new Error("State mismatch - possible CSRF attack"));return}he(r,$,i,t).then(a).catch(l);}}catch{}},100);setTimeout(()=>{clearInterval(M),y.closed||y.close(),l(new Error("Login timed out"));},5*60*1e3);})}async function Ot(n){track("passport","standaloneLoginWithEmbedded");let e=W(n),t=await Tt(e,n.clientId),r={directLoginOptions:{directLoginMethod:t.directLoginMethod,marketingConsentStatus:t.marketingConsentStatus,...t.directLoginMethod==="email"&&t.email?{email:t.email}:{}}};return Ee(n,r)}async function Lt(n,e){track("passport","standaloneLoginWithRedirect");let{url:t,verifier:r,state:o}=await fe(n,e);_t({state:o,verifier:r,redirectUri:n.redirectUri}),window.location.href=t;}async function Pt(n){if(track("passport","standaloneHandleCallback"),typeof window>"u")return;let e=new URLSearchParams(window.location.search),t=e.get("code"),r=e.get("state"),o=e.get("error"),i=e.get("error_description");if(o)throw new Error(i||o);if(!t)return;let s=yt();if(!s)throw new Error("No PKCE data found. Login may have been initiated in a different session.");if(r!==s.state)throw pe(),new Error("State mismatch - possible CSRF attack");let a=await he(n,t,s.verifier,s.redirectUri);return pe(),a}
|
|
387
|
+
`,document.head.appendChild(e);};getEmbeddedLoginIFrame=()=>{let e=document.createElement("iframe");return e.id=J,e.src=this.getHref(),e.style.height="100vh",e.style.width="100vw",e.style.maxHeight=`${ae}px`,e.style.maxWidth=`${de}px`,e.style.borderRadius=le,e.style.opacity="0",e.style.transform="scale(0.6)",e.style.animation="passportEmbeddedLoginPromptPopBounceIn 1s ease forwards",n.appendIFrameStylesIfNeeded(),e};displayEmbeddedLoginPrompt(){return new Promise((e,t)=>{let r=this.getEmbeddedLoginIFrame(),i=({data:o,origin:s})=>{if(!(s!==this.config.authenticationDomain||o.eventType!==V))switch(o.messageType){case"login_method_selected":{let l=o.payload;window.removeEventListener("message",i),u.remove(),e(l);break}case"login_prompt_error":{window.removeEventListener("message",i),u.remove(),t(new Error("Error during embedded login prompt",{cause:o.payload}));break}case"login_prompt_closed":{window.removeEventListener("message",i),u.remove(),t(new Error("Popup closed by user"));break}default:window.removeEventListener("message",i),u.remove(),t(new Error(`Unsupported message type: ${o.messageType}`));break}};window.addEventListener("message",i),u.appendOverlay(r,()=>{window.removeEventListener("message",i),u.remove(),t(new Error("Popup closed by user"));});})}};var C=class{listeners=new Map;emit(e,...t){let r=this.listeners.get(e);!r||r.size===0||[...r].forEach(i=>{i(...t);});}on(e,t){let r=this.listeners.get(e)??new Set;r.add(t),this.listeners.set(e,r);}removeListener(e,t){let r=this.listeners.get(e);r&&(r.delete(t),r.size===0&&this.listeners.delete(e));}};var c=async(n,e,t=!0,r=!0)=>{let i=trackFlow("passport",e,t);try{return await n(i)}catch(o){throw o instanceof Error?trackError("passport",e,o,{flowId:i.details.flowId}):i.addEvent("errored"),o}finally{r&&i.addEvent("End");}};var ue=()=>typeof globalThis<"u"?globalThis:typeof self<"u"?self:typeof window<"u"?window:typeof global<"u"?global:{},me=n=>{let e=n.replace(/-/g,"+").replace(/_/g,"/"),t=e.length%4===0?"":"=".repeat(4-e.length%4);return e+t},ge=n=>{let e=ue();if(typeof e.atob!="function")return null;let t=e.atob(n),r=new Uint8Array(t.length);for(let o=0;o<t.length;o+=1)r[o]=t.charCodeAt(o);if(typeof e.TextDecoder=="function")return new e.TextDecoder("utf-8").decode(r);let i="";for(let o=0;o<r.length;o+=1)i+=String.fromCharCode(r[o]);return i},fe=n=>{if(typeof Buffer<"u")return Buffer.from(n,"base64").toString("utf-8");let e=ge(n);if(e===null)throw new Error("Base64 decoding is not supported in this environment");return e},f=n=>{if(typeof n!="string")throw new Error("JWT must be a string");let e=n.split(".");if(e.length<2)throw new Error("Invalid JWT: payload segment is missing");let t=e[1],r=fe(me(t));try{return JSON.parse(r)}catch{throw new Error("Invalid JWT payload: unable to parse JSON")}};var j="pkce_state",Q="pkce_verifier",Ee=3600,O=class{isTokenValid(e){try{let r=f(e).exp??0,i=Date.now()/1e3+Ee;return r>i}catch{return !1}}savePKCEData(e){localStorage.setItem(j,e.state),localStorage.setItem(Q,e.verifier);}getPKCEData(){let e=localStorage.getItem(j),t=localStorage.getItem(Q);return e&&t?{state:e,verifier:t}:null}};var he=(...n)=>{if(typeof process>"u")return;process?.env?.JEST_WORKER_ID===void 0&&console.warn(...n);},_={warn:he};function q(n){try{let e=f(n),t=Math.floor(Date.now()/1e3);return e.exp?e.exp<=t+30:!0}catch{return !0}}function X(n){let{id_token:e,access_token:t}=n;return !t||!e?!0:q(t)||q(e)}var T=class{disableGenericPopupOverlay;disableBlockedPopupOverlay;overlay;isBlockedOverlay;tryAgainListener;onCloseListener;constructor(e,t=!1){this.disableBlockedPopupOverlay=e.disableBlockedPopupOverlay||!1,this.disableGenericPopupOverlay=e.disableGenericPopupOverlay||!1,this.isBlockedOverlay=t;}append(e,t){this.shouldAppendOverlay()&&(this.appendOverlay(),this.updateTryAgainButton(e),this.updateCloseButton(t));}update(e){this.updateTryAgainButton(e);}remove(){this.overlay&&this.overlay.remove();}shouldAppendOverlay(){return !(this.disableGenericPopupOverlay&&this.disableBlockedPopupOverlay||this.disableGenericPopupOverlay&&!this.isBlockedOverlay||this.disableBlockedPopupOverlay&&this.isBlockedOverlay)}appendOverlay(){if(!this.overlay){k({id:"link-googleapis",href:"https://fonts.googleapis.com"}),k({id:"link-gstatic",href:"https://fonts.gstatic.com",crossOrigin:"anonymous"}),k({id:"link-roboto",href:"https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,400;0,500;0,700;1,400;1,500;1,700&display=swap",rel:"stylesheet"});let t=document.createElement("div");t.innerHTML=this.isBlockedOverlay?$():z(),document.body.insertAdjacentElement("beforeend",t),this.overlay=t;}}updateTryAgainButton(e){let t=document.getElementById(w);t&&(this.tryAgainListener&&t.removeEventListener("click",this.tryAgainListener),this.tryAgainListener=e,t.addEventListener("click",e));}updateCloseButton(e){let t=document.getElementById(A);t&&(this.onCloseListener&&t.removeEventListener("click",this.onCloseListener),this.onCloseListener=e,t.addEventListener("click",e));}};var b=class{storage;constructor(e,t){this.storage=Ce.createInstance({name:e,driver:t});}get length(){return this.storage.length()}clear(){return this.storage.clear()}getItem(e){return this.storage.getItem(e)}key(e){return this.storage.key(e)}async removeItem(e){await this.storage.removeItem(e);}async setItem(e,t){await this.storage.setItem(e,t);}};var be={"Content-Type":"application/x-www-form-urlencoded"},Ue=n=>{if(n)try{return JSON.parse(n)}catch{return}},xe=(n,e,t)=>{if(n&&typeof n=="object"){let r=n,i=r.error_description??r.message??r.error;if(typeof i=="string"&&i.trim().length>0)return i}return e.trim().length>0?e:`Token request failed with status ${t}`},Me="/v2/logout",Se="/im-logged-out",Ne="/authorize",De=n=>n?Se:Me,Fe=n=>{let{authenticationDomain:e,oidcConfiguration:t}=n,r;n.crossSdkBridgeEnabled?r=new b("ImmutableSDKPassport",Ce.INDEXEDDB):typeof window<"u"?r=window.localStorage:r=new InMemoryWebStorage;let i=new WebStorageStateStore({store:r}),o=new URL(De(n.crossSdkBridgeEnabled),e.replace(/^(?:https?:\/\/)?(.*)/,"https://$1"));return o.searchParams.set("client_id",t.clientId),t.logoutRedirectUri&&o.searchParams.set("returnTo",t.logoutRedirectUri),{authority:e,redirect_uri:t.redirectUri,popup_redirect_uri:t.popupRedirectUri||t.redirectUri,client_id:t.clientId,metadata:{authorization_endpoint:`${e}/authorize`,token_endpoint:`${e}/oauth/token`,userinfo_endpoint:`${e}/userinfo`,end_session_endpoint:o.toString(),revocation_endpoint:`${e}/oauth/revoke`},automaticSilentRenew:!1,scope:t.scope,userStore:i,revokeTokenTypes:["refresh_token"],extraQueryParams:{...t.audience?{audience:t.audience}:{}}}};function N(n){return btoa(String.fromCharCode(...new Uint8Array(n))).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}async function He(n){let t=new TextEncoder().encode(n);return window.crypto.subtle.digest("SHA-256",t)}var D=class n{config;userManager;deviceCredentialsManager;embeddedLoginPrompt;logoutMode;refreshingPromise=null;eventEmitter;constructor(e){this.config=new y(e),this.embeddedLoginPrompt=new v(this.config),this.userManager=new UserManager(Fe(this.config)),this.deviceCredentialsManager=new O,this.logoutMode=this.config.oidcConfiguration.logoutMode||"redirect",this.eventEmitter=new C,track("passport","initialise");}async login(e){return c(async()=>{let{useCachedSession:t=!1,useSilentLogin:r}=e||{},i=null;try{i=await this.getUserInternal();}catch(o){if(o instanceof Error&&!o.message.includes("Unknown or invalid refresh token")&&trackError("passport","login",o),t)throw o;_.warn("Failed to retrieve a cached user session",o);}if(!i&&r)i=await this.forceUserRefreshInternal();else if(!i&&!t){if(e?.useRedirectFlow)return await this.loginWithRedirectInternal(e?.directLoginOptions),null;i=await this.loginWithPopup(e?.directLoginOptions);}return i&&this.handleSuccessfulLogin(i),i},"login")}async loginWithRedirect(e){await this.loginWithRedirectInternal(e);}async loginCallback(){return c(async()=>{let e=await this.loginCallbackInternal();return e&&this.handleSuccessfulLogin(e),e},"loginCallback")}async logout(){await c(async()=>{await this.logoutInternal(),this.eventEmitter.emit("loggedOut");},"logout");}async getUser(){return this.getUserInternal()}async getUserOrLogin(){let e=null;try{e=await this.getUserInternal();}catch(r){_.warn("Failed to retrieve a cached user session",r);}if(e)return e;let t=await this.loginWithPopup();return this.handleSuccessfulLogin(t),t}async getUserZkEvm(){return this.getUserZkEvmInternal()}async getIdToken(){return c(async()=>(await this.getUserInternal())?.idToken,"getIdToken",!1)}async getAccessToken(){return c(async()=>(await this.getUserInternal())?.accessToken,"getAccessToken",!1,!1)}async isLoggedIn(){return await this.getUser()!==null}async forceUserRefresh(){return this.forceUserRefreshInternal()}forceUserRefreshInBackground(){this.forceUserRefreshInBackgroundInternal();}async loginWithPKCEFlow(e,t){return c(async()=>this.getPKCEAuthorizationUrl(e,t),"loginWithPKCEFlow")}async loginWithPKCEFlowCallback(e,t){return c(async()=>{let r=await this.loginWithPKCEFlowCallbackInternal(e,t);return this.handleSuccessfulLogin(r),r},"loginWithPKCEFlowCallback")}async storeTokens(e){return c(async()=>{let t=await this.storeTokensInternal(e);return this.handleSuccessfulLogin(t),t},"storeTokens")}async getLogoutUrl(){return c(async()=>(await this.userManager.removeUser(),this.eventEmitter.emit("loggedOut"),await this.getLogoutUrlInternal()||void 0),"getLogoutUrl")}async logoutSilentCallback(e){return c(()=>this.userManager.signoutSilentCallback(e),"logoutSilentCallback")}getConfig(){return this.config}async getClientId(){return this.config.oidcConfiguration.clientId}handleSuccessfulLogin(e){this.eventEmitter.emit("loggedIn",e),identify({passportId:e.profile.sub});}buildExtraQueryParams(e,t){let r={...this.userManager.settings?.extraQueryParams??{},rid:getDetail(Detail.RUNTIME_ID)||""};if(e){if(e.directLoginMethod==="email"){let i=e.email;i&&(r.direct=e.directLoginMethod,r.email=i);}else r.direct=e.directLoginMethod;e.marketingConsentStatus&&(r.marketingConsent=e.marketingConsentStatus);}return t&&(r.im_passport_trace_id=t),r}async loginWithRedirectInternal(e){await this.userManager.clearStaleState(),await g(async()=>{let t=this.buildExtraQueryParams(e);await this.userManager.signinRedirect({extraQueryParams:t});},"AUTHENTICATION_ERROR");}async loginWithPopup(e){return g(async()=>{let t,r;if(e)t=e;else if(!this.config.popupOverlayOptions?.disableHeadlessLoginPromptOverlay){let{imPassportTraceId:s,...l}=await this.embeddedLoginPrompt.displayEmbeddedLoginPrompt();t=l,r=s;}let i=window.crypto.randomUUID(),o=async()=>{let s=this.buildExtraQueryParams(t,r);return this.userManager.signinPopup({extraQueryParams:s,popupWindowFeatures:{width:410,height:450},popupWindowTarget:i,popupAbortOnClose:!0})};return new Promise((s,l)=>{o().then(m=>s(n.mapOidcUserToDomainModel(m))).catch(m=>{if(!(m instanceof Error)||m.message!=="Attempted to navigate on a disposed window"){l(m);return}let L=!1,d=new T(this.config.popupOverlayOptions||{},!0);d.append(async()=>{try{if(L)window.open("",i);else {L=!0;let E=await o();d.remove(),s(n.mapOidcUserToDomainModel(E));}}catch(E){d.remove(),l(E);}},()=>{d.remove(),l(new Error("Popup closed by user"));});});})},"AUTHENTICATION_ERROR")}static mapOidcUserToDomainModel=e=>{let t,r;if(e.id_token){let s=f(e.id_token);t=s?.passport,s?.username&&(r=s?.username);}let i={expired:e.expired,idToken:e.id_token,accessToken:e.access_token,refreshToken:e.refresh_token,profile:{sub:e.profile.sub,email:e.profile.email,nickname:e.profile.nickname,username:r}};t?.zkevm_eth_address&&t?.zkevm_user_admin_address&&(i.zkEvm={ethAddress:t.zkevm_eth_address,userAdminAddress:t.zkevm_user_admin_address});let o=Object.values(I).filter(s=>s!=="zkevm");for(let s of o){let l=t?.[s];l?.eth_address&&l?.user_admin_address&&(i[s]={ethAddress:l.eth_address,userAdminAddress:l.user_admin_address});}return i};static mapDeviceTokenResponseToOidcUser=e=>{let t=f(e.id_token);return new User({id_token:e.id_token,access_token:e.access_token,refresh_token:e.refresh_token,token_type:e.token_type,profile:{sub:t.sub,iss:t.iss,aud:t.aud,exp:t.exp,iat:t.iat,email:t.email,nickname:t.nickname,passport:t.passport,...t.username?{username:t.username}:{}}})};async loginCallbackInternal(){return g(async()=>{let e=await this.userManager.signinCallback();if(e)return n.mapOidcUserToDomainModel(e)},"AUTHENTICATION_ERROR")}async getPKCEAuthorizationUrl(e,t){let r=N(window.crypto.getRandomValues(new Uint8Array(32))),i=N(await He(r)),o=N(window.crypto.getRandomValues(new Uint8Array(32))),{redirectUri:s,scope:l,audience:m,clientId:L}=this.config.oidcConfiguration;this.deviceCredentialsManager.savePKCEData({state:o,verifier:r});let d=new URL(Ne,this.config.authenticationDomain);if(d.searchParams.set("response_type","code"),d.searchParams.set("code_challenge",i),d.searchParams.set("code_challenge_method","S256"),d.searchParams.set("client_id",L),d.searchParams.set("redirect_uri",s),d.searchParams.set("state",o),l&&d.searchParams.set("scope",l),m&&d.searchParams.set("audience",m),e){if(e.directLoginMethod==="email"){let E=e.email;E&&(d.searchParams.set("direct",e.directLoginMethod),d.searchParams.set("email",E));}else d.searchParams.set("direct",e.directLoginMethod);e.marketingConsentStatus&&d.searchParams.set("marketingConsent",e.marketingConsentStatus);}return t&&d.searchParams.set("im_passport_trace_id",t),d.toString()}async loginWithPKCEFlowCallbackInternal(e,t){return g(async()=>{let r=this.deviceCredentialsManager.getPKCEData();if(!r)throw new Error("No code verifier or state for PKCE");if(t!==r.state)throw new Error("Provided state does not match stored state");let i=await this.getPKCEToken(e,r.verifier),o=n.mapDeviceTokenResponseToOidcUser(i),s=n.mapOidcUserToDomainModel(o);return await this.userManager.storeUser(o),s},"AUTHENTICATION_ERROR")}async getPKCEToken(e,t){let r=await fetch(`${this.config.authenticationDomain}/oauth/token`,{method:"POST",headers:be,body:new URLSearchParams({client_id:this.config.oidcConfiguration.clientId,grant_type:"authorization_code",code_verifier:t,code:e,redirect_uri:this.config.oidcConfiguration.redirectUri})}),i=await r.text(),o=Ue(i);if(!r.ok)throw new Error(xe(o,i,r.status));if(!o||typeof o!="object")throw new Error("Token endpoint returned an invalid response");return o}async storeTokensInternal(e){return g(async()=>{let t=n.mapDeviceTokenResponseToOidcUser(e),r=n.mapOidcUserToDomainModel(t);return await this.userManager.storeUser(t),r},"AUTHENTICATION_ERROR")}async logoutInternal(){await g(async()=>{await this.userManager.revokeTokens(["refresh_token"]),this.logoutMode==="silent"?await this.userManager.signoutSilent():await this.userManager.signoutRedirect();},"LOGOUT_ERROR");}async getLogoutUrlInternal(){let e=this.userManager.settings?.metadata?.end_session_endpoint;return e||(_.warn("Failed to get logout URL"),null)}forceUserRefreshInBackgroundInternal(){this.refreshTokenAndUpdatePromise().catch(e=>{_.warn("Failed to refresh user token",e);});}async forceUserRefreshInternal(){return this.refreshTokenAndUpdatePromise().catch(e=>(_.warn("Failed to refresh user token",e),null))}async refreshTokenAndUpdatePromise(){return this.refreshingPromise?this.refreshingPromise:(this.refreshingPromise=new Promise((e,t)=>{(async()=>{try{let r=await this.userManager.signinSilent();if(r){e(n.mapOidcUserToDomainModel(r));return}e(null);}catch(r){let i="AUTHENTICATION_ERROR",o="Failed to refresh token",s=!0;if(r instanceof ErrorTimeout?(i="SILENT_LOGIN_ERROR",o=`${o}: ${r.message}`,s=!1):r instanceof ErrorResponse?(i="NOT_LOGGED_IN_ERROR",o=`${o}: ${r.message||r.error_description}`):r instanceof Error?o=`${o}: ${r.message}`:typeof r=="string"&&(o=`${o}: ${r}`),s)try{await this.userManager.removeUser();}catch(l){l instanceof Error&&(o=`${o}: Failed to remove user: ${l.message}`);}t(new p(o,i));}finally{this.refreshingPromise=null;}})();}),this.refreshingPromise)}async getUserInternal(e=t=>!0){if(this.refreshingPromise){let r=await this.refreshingPromise;return r&&e(r)?r:null}let t=await this.userManager.getUser();if(!t)return null;if(!X(t)){let r=n.mapOidcUserToDomainModel(t);if(r&&e(r))return r}if(t.refresh_token){let r=await this.refreshTokenAndUpdatePromise();if(r&&e(r))return r}return null}async getUserZkEvmInternal(){let e=await this.getUserInternal(x);if(!e)throw new Error("Failed to obtain a User with the required ZkEvm attributes");return e}};
|
|
440
388
|
|
|
441
|
-
export {
|
|
389
|
+
export { D as Auth, y as AuthConfiguration, M as AuthEvents, I as EvmChain, H as MarketingConsentStatus, p as PassportError, P as PassportErrorType, F as RollupType, C as TypedEventEmitter, f as decodeJwtPayload, U as isAPIError, x as isUserZkEvm, g as withPassportError };
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
export { Auth } from './Auth';
|
|
2
2
|
export { AuthConfiguration, type IAuthConfiguration } from './config';
|
|
3
|
-
export type { User, UserProfile, UserZkEvm, DirectLoginMethod, DirectLoginOptions, LoginOptions, DeviceTokenResponse, OidcConfiguration, AuthModuleConfiguration, PopupOverlayOptions, PassportMetadata, PassportChainMetadata, ChainAddress, IdTokenPayload, PKCEData, AuthEventMap,
|
|
3
|
+
export type { User, UserProfile, UserZkEvm, DirectLoginMethod, DirectLoginOptions, LoginOptions, DeviceTokenResponse, OidcConfiguration, AuthModuleConfiguration, PopupOverlayOptions, PassportMetadata, PassportChainMetadata, ChainAddress, IdTokenPayload, PKCEData, AuthEventMap, } from './types';
|
|
4
4
|
export { isUserZkEvm, RollupType, EvmChain, MarketingConsentStatus, AuthEvents, } from './types';
|
|
5
5
|
export { default as TypedEventEmitter } from './utils/typedEventEmitter';
|
|
6
6
|
export { PassportError, PassportErrorType, withPassportError, isAPIError, } from './errors';
|
|
7
7
|
export { decodeJwtPayload } from './utils/jwt';
|
|
8
|
-
export { loginWithPopup, loginWithEmbedded, loginWithRedirect, handleLoginCallback, type LoginConfig, type TokenResponse, type StandaloneLoginOptions, } from './login/standalone';
|
package/dist/types/types.d.ts
CHANGED
|
@@ -143,41 +143,13 @@ export type LoginOptions = {
|
|
|
143
143
|
*/
|
|
144
144
|
export declare enum AuthEvents {
|
|
145
145
|
LOGGED_OUT = "loggedOut",
|
|
146
|
-
LOGGED_IN = "loggedIn"
|
|
147
|
-
/**
|
|
148
|
-
* Emitted when tokens are refreshed via signinSilent().
|
|
149
|
-
* This is critical for refresh token rotation - when client-side refresh happens,
|
|
150
|
-
* the new tokens must be synced to server-side session to prevent race conditions.
|
|
151
|
-
*/
|
|
152
|
-
TOKEN_REFRESHED = "tokenRefreshed",
|
|
153
|
-
/**
|
|
154
|
-
* Emitted when the user is removed from local storage due to a permanent auth error.
|
|
155
|
-
* Only emitted for errors where the refresh token is truly invalid:
|
|
156
|
-
* - invalid_grant: refresh token expired, revoked, or already used
|
|
157
|
-
* - login_required: user must re-authenticate
|
|
158
|
-
* - consent_required / interaction_required: user must interact with auth server
|
|
159
|
-
*
|
|
160
|
-
* NOT emitted for transient errors (network, timeout, server errors) - user stays logged in.
|
|
161
|
-
* Consumers should sync this state by clearing their session (e.g., NextAuth signOut).
|
|
162
|
-
*/
|
|
163
|
-
USER_REMOVED = "userRemoved"
|
|
146
|
+
LOGGED_IN = "loggedIn"
|
|
164
147
|
}
|
|
165
|
-
/**
|
|
166
|
-
* Error reason for USER_REMOVED event.
|
|
167
|
-
* Note: Network/timeout errors do NOT emit USER_REMOVED (user stays logged in),
|
|
168
|
-
* so 'network_error' is not a valid reason.
|
|
169
|
-
*/
|
|
170
|
-
export type UserRemovedReason = 'refresh_token_invalid' | 'refresh_failed' | 'unknown';
|
|
171
148
|
/**
|
|
172
149
|
* Event map for typed event emitter
|
|
173
150
|
*/
|
|
174
151
|
export interface AuthEventMap extends Record<string, any> {
|
|
175
152
|
[AuthEvents.LOGGED_OUT]: [];
|
|
176
153
|
[AuthEvents.LOGGED_IN]: [User];
|
|
177
|
-
[AuthEvents.TOKEN_REFRESHED]: [User];
|
|
178
|
-
[AuthEvents.USER_REMOVED]: [{
|
|
179
|
-
reason: UserRemovedReason;
|
|
180
|
-
error?: string;
|
|
181
|
-
}];
|
|
182
154
|
}
|
|
183
155
|
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@imtbl/auth",
|
|
3
|
-
"version": "2.12.5-alpha.
|
|
3
|
+
"version": "2.12.5-alpha.23",
|
|
4
4
|
"description": "Authentication SDK for Immutable",
|
|
5
5
|
"author": "Immutable",
|
|
6
6
|
"bugs": "https://github.com/immutable/ts-immutable-sdk/issues",
|
|
@@ -25,18 +25,18 @@
|
|
|
25
25
|
}
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@imtbl/generated-clients": "2.12.5-alpha.
|
|
29
|
-
"@imtbl/metrics": "2.12.5-alpha.
|
|
28
|
+
"@imtbl/generated-clients": "2.12.5-alpha.23",
|
|
29
|
+
"@imtbl/metrics": "2.12.5-alpha.23",
|
|
30
30
|
"localforage": "^1.10.0",
|
|
31
31
|
"oidc-client-ts": "3.4.1"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
|
-
"@swc/core": "^1.
|
|
34
|
+
"@swc/core": "^1.3.36",
|
|
35
35
|
"@swc/jest": "^0.2.37",
|
|
36
36
|
"@types/jest": "^29.5.12",
|
|
37
|
-
"@types/node": "^
|
|
37
|
+
"@types/node": "^18.14.2",
|
|
38
38
|
"@jest/test-sequencer": "^29.7.0",
|
|
39
|
-
"jest": "^29.
|
|
39
|
+
"jest": "^29.4.3",
|
|
40
40
|
"jest-environment-jsdom": "^29.4.3",
|
|
41
41
|
"ts-node": "^10.9.1",
|
|
42
42
|
"tsup": "^8.3.0",
|
package/src/Auth.test.ts
CHANGED
|
@@ -268,231 +268,6 @@ describe('Auth', () => {
|
|
|
268
268
|
});
|
|
269
269
|
});
|
|
270
270
|
|
|
271
|
-
describe('refreshTokenAndUpdatePromise', () => {
|
|
272
|
-
it('emits TOKEN_REFRESHED event when signinSilent succeeds', async () => {
|
|
273
|
-
const mockOidcUser = {
|
|
274
|
-
id_token: 'new-id',
|
|
275
|
-
access_token: 'new-access',
|
|
276
|
-
refresh_token: 'new-refresh',
|
|
277
|
-
expired: false,
|
|
278
|
-
profile: { sub: 'user-123', email: 'test@example.com', nickname: 'tester' },
|
|
279
|
-
};
|
|
280
|
-
|
|
281
|
-
(decodeJwtPayload as jest.Mock).mockReturnValue({
|
|
282
|
-
username: undefined,
|
|
283
|
-
passport: undefined,
|
|
284
|
-
});
|
|
285
|
-
|
|
286
|
-
const auth = Object.create(Auth.prototype) as Auth;
|
|
287
|
-
const mockEventEmitter = { emit: jest.fn() };
|
|
288
|
-
const mockUserManager = {
|
|
289
|
-
signinSilent: jest.fn().mockResolvedValue(mockOidcUser),
|
|
290
|
-
};
|
|
291
|
-
|
|
292
|
-
(auth as any).eventEmitter = mockEventEmitter;
|
|
293
|
-
(auth as any).userManager = mockUserManager;
|
|
294
|
-
(auth as any).refreshingPromise = null;
|
|
295
|
-
|
|
296
|
-
const user = await (auth as any).refreshTokenAndUpdatePromise();
|
|
297
|
-
|
|
298
|
-
expect(user).toBeDefined();
|
|
299
|
-
expect(user.accessToken).toBe('new-access');
|
|
300
|
-
expect(mockEventEmitter.emit).toHaveBeenCalledWith(
|
|
301
|
-
AuthEvents.TOKEN_REFRESHED,
|
|
302
|
-
expect.objectContaining({
|
|
303
|
-
accessToken: 'new-access',
|
|
304
|
-
refreshToken: 'new-refresh',
|
|
305
|
-
}),
|
|
306
|
-
);
|
|
307
|
-
});
|
|
308
|
-
|
|
309
|
-
it('does not emit TOKEN_REFRESHED event when signinSilent returns null', async () => {
|
|
310
|
-
const auth = Object.create(Auth.prototype) as Auth;
|
|
311
|
-
const mockEventEmitter = { emit: jest.fn() };
|
|
312
|
-
const mockUserManager = {
|
|
313
|
-
signinSilent: jest.fn().mockResolvedValue(null),
|
|
314
|
-
};
|
|
315
|
-
|
|
316
|
-
(auth as any).eventEmitter = mockEventEmitter;
|
|
317
|
-
(auth as any).userManager = mockUserManager;
|
|
318
|
-
(auth as any).refreshingPromise = null;
|
|
319
|
-
|
|
320
|
-
const user = await (auth as any).refreshTokenAndUpdatePromise();
|
|
321
|
-
|
|
322
|
-
expect(user).toBeNull();
|
|
323
|
-
expect(mockEventEmitter.emit).not.toHaveBeenCalled();
|
|
324
|
-
});
|
|
325
|
-
|
|
326
|
-
it('emits USER_REMOVED event for invalid_grant error', async () => {
|
|
327
|
-
const auth = Object.create(Auth.prototype) as Auth;
|
|
328
|
-
const mockEventEmitter = { emit: jest.fn() };
|
|
329
|
-
const mockUserManager = {
|
|
330
|
-
signinSilent: jest.fn().mockRejectedValue(
|
|
331
|
-
Object.assign(new Error('invalid_grant'), {
|
|
332
|
-
error: 'invalid_grant',
|
|
333
|
-
error_description: 'Unknown or invalid refresh token',
|
|
334
|
-
}),
|
|
335
|
-
),
|
|
336
|
-
removeUser: jest.fn().mockResolvedValue(undefined),
|
|
337
|
-
};
|
|
338
|
-
|
|
339
|
-
// Make the error an instance of ErrorResponse
|
|
340
|
-
const { ErrorResponse } = jest.requireActual('oidc-client-ts');
|
|
341
|
-
const errorResponse = new ErrorResponse({
|
|
342
|
-
error: 'invalid_grant',
|
|
343
|
-
error_description: 'Unknown or invalid refresh token',
|
|
344
|
-
});
|
|
345
|
-
mockUserManager.signinSilent.mockRejectedValue(errorResponse);
|
|
346
|
-
|
|
347
|
-
(auth as any).eventEmitter = mockEventEmitter;
|
|
348
|
-
(auth as any).userManager = mockUserManager;
|
|
349
|
-
(auth as any).refreshingPromise = null;
|
|
350
|
-
|
|
351
|
-
await expect((auth as any).refreshTokenAndUpdatePromise()).rejects.toThrow();
|
|
352
|
-
|
|
353
|
-
expect(mockEventEmitter.emit).toHaveBeenCalledWith(
|
|
354
|
-
AuthEvents.USER_REMOVED,
|
|
355
|
-
expect.objectContaining({
|
|
356
|
-
reason: 'refresh_failed',
|
|
357
|
-
}),
|
|
358
|
-
);
|
|
359
|
-
expect(mockUserManager.removeUser).toHaveBeenCalled();
|
|
360
|
-
});
|
|
361
|
-
|
|
362
|
-
it('emits USER_REMOVED event for login_required error', async () => {
|
|
363
|
-
const auth = Object.create(Auth.prototype) as Auth;
|
|
364
|
-
const mockEventEmitter = { emit: jest.fn() };
|
|
365
|
-
const mockUserManager = {
|
|
366
|
-
signinSilent: jest.fn(),
|
|
367
|
-
removeUser: jest.fn().mockResolvedValue(undefined),
|
|
368
|
-
};
|
|
369
|
-
|
|
370
|
-
const { ErrorResponse } = jest.requireActual('oidc-client-ts');
|
|
371
|
-
const errorResponse = new ErrorResponse({
|
|
372
|
-
error: 'login_required',
|
|
373
|
-
error_description: 'User must re-authenticate',
|
|
374
|
-
});
|
|
375
|
-
mockUserManager.signinSilent.mockRejectedValue(errorResponse);
|
|
376
|
-
|
|
377
|
-
(auth as any).eventEmitter = mockEventEmitter;
|
|
378
|
-
(auth as any).userManager = mockUserManager;
|
|
379
|
-
(auth as any).refreshingPromise = null;
|
|
380
|
-
|
|
381
|
-
await expect((auth as any).refreshTokenAndUpdatePromise()).rejects.toThrow();
|
|
382
|
-
|
|
383
|
-
expect(mockEventEmitter.emit).toHaveBeenCalledWith(
|
|
384
|
-
AuthEvents.USER_REMOVED,
|
|
385
|
-
expect.objectContaining({
|
|
386
|
-
reason: 'refresh_failed',
|
|
387
|
-
}),
|
|
388
|
-
);
|
|
389
|
-
expect(mockUserManager.removeUser).toHaveBeenCalled();
|
|
390
|
-
});
|
|
391
|
-
|
|
392
|
-
it('emits USER_REMOVED event for network errors', async () => {
|
|
393
|
-
const auth = Object.create(Auth.prototype) as Auth;
|
|
394
|
-
const mockEventEmitter = { emit: jest.fn() };
|
|
395
|
-
const mockUserManager = {
|
|
396
|
-
signinSilent: jest.fn().mockRejectedValue(new Error('Network error: Failed to fetch')),
|
|
397
|
-
removeUser: jest.fn().mockResolvedValue(undefined),
|
|
398
|
-
};
|
|
399
|
-
|
|
400
|
-
(auth as any).eventEmitter = mockEventEmitter;
|
|
401
|
-
(auth as any).userManager = mockUserManager;
|
|
402
|
-
(auth as any).refreshingPromise = null;
|
|
403
|
-
|
|
404
|
-
await expect((auth as any).refreshTokenAndUpdatePromise()).rejects.toThrow();
|
|
405
|
-
|
|
406
|
-
expect(mockEventEmitter.emit).toHaveBeenCalledWith(
|
|
407
|
-
AuthEvents.USER_REMOVED,
|
|
408
|
-
expect.objectContaining({
|
|
409
|
-
reason: 'refresh_failed',
|
|
410
|
-
}),
|
|
411
|
-
);
|
|
412
|
-
expect(mockUserManager.removeUser).toHaveBeenCalled();
|
|
413
|
-
});
|
|
414
|
-
|
|
415
|
-
it('emits USER_REMOVED event for server_error OAuth error', async () => {
|
|
416
|
-
const auth = Object.create(Auth.prototype) as Auth;
|
|
417
|
-
const mockEventEmitter = { emit: jest.fn() };
|
|
418
|
-
const mockUserManager = {
|
|
419
|
-
signinSilent: jest.fn(),
|
|
420
|
-
removeUser: jest.fn().mockResolvedValue(undefined),
|
|
421
|
-
};
|
|
422
|
-
|
|
423
|
-
const { ErrorResponse } = jest.requireActual('oidc-client-ts');
|
|
424
|
-
const errorResponse = new ErrorResponse({
|
|
425
|
-
error: 'server_error',
|
|
426
|
-
error_description: 'Internal server error',
|
|
427
|
-
});
|
|
428
|
-
mockUserManager.signinSilent.mockRejectedValue(errorResponse);
|
|
429
|
-
|
|
430
|
-
(auth as any).eventEmitter = mockEventEmitter;
|
|
431
|
-
(auth as any).userManager = mockUserManager;
|
|
432
|
-
(auth as any).refreshingPromise = null;
|
|
433
|
-
|
|
434
|
-
await expect((auth as any).refreshTokenAndUpdatePromise()).rejects.toThrow();
|
|
435
|
-
|
|
436
|
-
expect(mockEventEmitter.emit).toHaveBeenCalledWith(
|
|
437
|
-
AuthEvents.USER_REMOVED,
|
|
438
|
-
expect.objectContaining({
|
|
439
|
-
reason: 'refresh_failed',
|
|
440
|
-
}),
|
|
441
|
-
);
|
|
442
|
-
expect(mockUserManager.removeUser).toHaveBeenCalled();
|
|
443
|
-
});
|
|
444
|
-
|
|
445
|
-
it('emits USER_REMOVED event for unknown errors (safer default)', async () => {
|
|
446
|
-
const auth = Object.create(Auth.prototype) as Auth;
|
|
447
|
-
const mockEventEmitter = { emit: jest.fn() };
|
|
448
|
-
const mockUserManager = {
|
|
449
|
-
signinSilent: jest.fn().mockRejectedValue(new Error('Some unknown error')),
|
|
450
|
-
removeUser: jest.fn().mockResolvedValue(undefined),
|
|
451
|
-
};
|
|
452
|
-
|
|
453
|
-
(auth as any).eventEmitter = mockEventEmitter;
|
|
454
|
-
(auth as any).userManager = mockUserManager;
|
|
455
|
-
(auth as any).refreshingPromise = null;
|
|
456
|
-
|
|
457
|
-
await expect((auth as any).refreshTokenAndUpdatePromise()).rejects.toThrow();
|
|
458
|
-
|
|
459
|
-
// Unknown errors should remove user (safer default)
|
|
460
|
-
expect(mockEventEmitter.emit).toHaveBeenCalledWith(
|
|
461
|
-
AuthEvents.USER_REMOVED,
|
|
462
|
-
expect.objectContaining({
|
|
463
|
-
reason: 'refresh_failed',
|
|
464
|
-
}),
|
|
465
|
-
);
|
|
466
|
-
expect(mockUserManager.removeUser).toHaveBeenCalled();
|
|
467
|
-
});
|
|
468
|
-
|
|
469
|
-
it('does not emit USER_REMOVED event for ErrorTimeout', async () => {
|
|
470
|
-
const auth = Object.create(Auth.prototype) as Auth;
|
|
471
|
-
const mockEventEmitter = { emit: jest.fn() };
|
|
472
|
-
const mockUserManager = {
|
|
473
|
-
signinSilent: jest.fn(),
|
|
474
|
-
removeUser: jest.fn().mockResolvedValue(undefined),
|
|
475
|
-
};
|
|
476
|
-
|
|
477
|
-
// Mock ErrorTimeout
|
|
478
|
-
const { ErrorTimeout } = jest.requireActual('oidc-client-ts');
|
|
479
|
-
const timeoutError = new ErrorTimeout('Silent sign-in timed out');
|
|
480
|
-
mockUserManager.signinSilent.mockRejectedValue(timeoutError);
|
|
481
|
-
|
|
482
|
-
(auth as any).eventEmitter = mockEventEmitter;
|
|
483
|
-
(auth as any).userManager = mockUserManager;
|
|
484
|
-
(auth as any).refreshingPromise = null;
|
|
485
|
-
|
|
486
|
-
await expect((auth as any).refreshTokenAndUpdatePromise()).rejects.toThrow();
|
|
487
|
-
|
|
488
|
-
expect(mockEventEmitter.emit).not.toHaveBeenCalledWith(
|
|
489
|
-
AuthEvents.USER_REMOVED,
|
|
490
|
-
expect.anything(),
|
|
491
|
-
);
|
|
492
|
-
expect(mockUserManager.removeUser).not.toHaveBeenCalled();
|
|
493
|
-
});
|
|
494
|
-
});
|
|
495
|
-
|
|
496
271
|
describe('loginWithPopup', () => {
|
|
497
272
|
let mockUserManager: any;
|
|
498
273
|
let originalCryptoRandomUUID: any;
|