@@ -534,6 +534,7 @@ async function executeXOriginSource(sourceIdx, buttonEl) {
534534 } ) ;
535535
536536 var data = await resp . json ( ) ;
537+ handleProxyResponse ( data , fullUrl ) ;
537538
538539 // Restore button
539540 if ( buttonEl ) {
@@ -1832,6 +1833,7 @@ function setAuthStatus(authenticated, message, authMethod) {
18321833 sessionStorage . removeItem ( 'anypoint_auth_method' ) ;
18331834 sessionStorage . removeItem ( 'anypoint_identity' ) ;
18341835 sessionStorage . removeItem ( 'anypoint_token_expires_at' ) ;
1836+ stopTtlTimer ( ) ;
18351837 }
18361838
18371839 updateAuthSummary ( ) ;
@@ -1875,16 +1877,16 @@ async function loginBearer() {
18751877 sessionStorage . setItem ( 'anypoint_token' , body . access_token ) ;
18761878 sessionStorage . setItem ( 'anypoint_identity' , username ) ;
18771879
1878- // Store token expiration time
1879- if ( body . expires_in ) {
1880- var expiresAt = Date . now ( ) + ( body . expires_in * 1000 ) ;
1881- sessionStorage . setItem ( 'anypoint_token_expires_at' , expiresAt . toString ( ) ) ;
1880+ var introspectResult = await introspectToken ( ) ;
1881+ if ( introspectResult && introspectResult . exp ) {
1882+ setTokenExpiration ( parseInt ( introspectResult . exp , 10 ) ) ;
1883+ } else {
1884+ setTokenExpiration ( Date . now ( ) + _SESSION_TTL ) ;
18821885 }
18831886
18841887 setAuthStatus ( true , null , 'Bearer' ) ;
18851888 showAuthMessage ( 'Login successful!' , false ) ;
18861889
1887- // Update playground panels with any environment variables that may have been set
18881890 if ( typeof updateAllPlaygroundPanelsFromEnvVars === 'function' ) {
18891891 updateAllPlaygroundPanelsFromEnvVars ( ) ;
18901892 }
@@ -1925,16 +1927,20 @@ async function loginOAuth2() {
19251927 sessionStorage . setItem ( 'anypoint_token' , body . access_token ) ;
19261928 sessionStorage . setItem ( 'anypoint_identity' , clientId ) ;
19271929
1928- // Store token expiration time
19291930 if ( body . expires_in ) {
1930- var expiresAt = Date . now ( ) + ( body . expires_in * 1000 ) ;
1931- sessionStorage . setItem ( 'anypoint_token_expires_at' , expiresAt . toString ( ) ) ;
1931+ setTokenExpiration ( Date . now ( ) + ( body . expires_in * 1000 ) ) ;
1932+ } else {
1933+ var introspectResult = await introspectToken ( ) ;
1934+ if ( introspectResult && introspectResult . exp ) {
1935+ setTokenExpiration ( parseInt ( introspectResult . exp , 10 ) ) ;
1936+ } else {
1937+ setTokenExpiration ( Date . now ( ) + _SESSION_TTL ) ;
1938+ }
19321939 }
19331940
19341941 setAuthStatus ( true , null , 'OAuth2' ) ;
19351942 showAuthMessage ( 'Token obtained successfully!' , false ) ;
19361943
1937- // Update playground panels with any environment variables that may have been set
19381944 if ( typeof updateAllPlaygroundPanelsFromEnvVars === 'function' ) {
19391945 updateAllPlaygroundPanelsFromEnvVars ( ) ;
19401946 }
@@ -1952,6 +1958,128 @@ function getAuthHeaders() {
19521958 return { } ;
19531959}
19541960
1961+ // ============================================================================
1962+ // Try It Out — Session TTL Management
1963+ // ============================================================================
1964+
1965+ var _ttlTimerId = null ;
1966+ var _ttlExpirationTimerId = null ;
1967+ var _TTL_CHECK_INTERVAL = 30000 ;
1968+ var _SESSION_TTL = 3600000 ;
1969+
1970+ function isAccountsUrl ( url ) {
1971+ try {
1972+ var path = new URL ( url ) . pathname ;
1973+ return path . startsWith ( '/accounts/' ) || path === '/accounts' ;
1974+ } catch ( e ) {
1975+ return url . indexOf ( '/accounts/' ) !== - 1 || url . indexOf ( '/accounts' ) === url . length - 9 ;
1976+ }
1977+ }
1978+
1979+ async function introspectToken ( ) {
1980+ var token = sessionStorage . getItem ( 'anypoint_token' ) ;
1981+ if ( ! token ) return null ;
1982+ var serverBase = getSelectedBaseUrl ( ) ;
1983+ try {
1984+ var resp = await fetch ( PROXY_URL , {
1985+ method : 'POST' ,
1986+ headers : { 'Content-Type' : 'application/json' } ,
1987+ body : JSON . stringify ( {
1988+ method : 'POST' ,
1989+ url : serverBase + '/accounts/oauth2/introspect' ,
1990+ headers : {
1991+ 'Content-Type' : 'application/json' ,
1992+ 'Authorization' : 'Bearer ' + token
1993+ } ,
1994+ body : JSON . stringify ( { token : token , token_type_hint : 'access_token' } )
1995+ } )
1996+ } ) ;
1997+ var data = await resp . json ( ) ;
1998+ if ( data . error ) return null ;
1999+ var body = JSON . parse ( data . body ) ;
2000+ return body ;
2001+ } catch ( e ) {
2002+ return null ;
2003+ }
2004+ }
2005+
2006+ function setTokenExpiration ( expMs ) {
2007+ sessionStorage . setItem ( 'anypoint_token_expires_at' , String ( expMs ) ) ;
2008+ startTtlTimer ( ) ;
2009+ scheduleExpirationCheck ( expMs ) ;
2010+ }
2011+
2012+ function scheduleExpirationCheck ( expMs ) {
2013+ if ( _ttlExpirationTimerId !== null ) {
2014+ clearTimeout ( _ttlExpirationTimerId ) ;
2015+ _ttlExpirationTimerId = null ;
2016+ }
2017+ var delay = expMs - Date . now ( ) ;
2018+ if ( delay <= 0 ) {
2019+ checkTtlExpiration ( ) ;
2020+ return ;
2021+ }
2022+ _ttlExpirationTimerId = setTimeout ( function ( ) {
2023+ _ttlExpirationTimerId = null ;
2024+ checkTtlExpiration ( ) ;
2025+ } , delay ) ;
2026+ }
2027+
2028+ function extendTokenExpiration ( ) {
2029+ var token = sessionStorage . getItem ( 'anypoint_token' ) ;
2030+ if ( ! token ) return ;
2031+ setTokenExpiration ( Date . now ( ) + _SESSION_TTL ) ;
2032+ }
2033+
2034+ function markTokenExpired ( ) {
2035+ sessionStorage . setItem ( 'anypoint_token_expires_at' , '0' ) ;
2036+ stopTtlTimer ( ) ;
2037+ updateAuthSummary ( ) ;
2038+ }
2039+
2040+ function startTtlTimer ( ) {
2041+ stopTtlTimer ( ) ;
2042+ _ttlTimerId = setInterval ( checkTtlExpiration , _TTL_CHECK_INTERVAL ) ;
2043+ }
2044+
2045+ function stopTtlTimer ( ) {
2046+ if ( _ttlTimerId !== null ) {
2047+ clearInterval ( _ttlTimerId ) ;
2048+ _ttlTimerId = null ;
2049+ }
2050+ if ( _ttlExpirationTimerId !== null ) {
2051+ clearTimeout ( _ttlExpirationTimerId ) ;
2052+ _ttlExpirationTimerId = null ;
2053+ }
2054+ }
2055+
2056+ async function checkTtlExpiration ( ) {
2057+ var token = sessionStorage . getItem ( 'anypoint_token' ) ;
2058+ if ( ! token ) {
2059+ stopTtlTimer ( ) ;
2060+ return ;
2061+ }
2062+ if ( ! isTokenExpired ( ) ) return ;
2063+
2064+ var result = await introspectToken ( ) ;
2065+ if ( result && result . active === true && result . exp ) {
2066+ setTokenExpiration ( parseInt ( result . exp , 10 ) ) ;
2067+ updateAuthSummary ( ) ;
2068+ } else if ( result && result . active === false ) {
2069+ markTokenExpired ( ) ;
2070+ }
2071+ }
2072+
2073+ function handleProxyResponse ( data , requestUrl ) {
2074+ if ( data . status === 401 ) {
2075+ markTokenExpired ( ) ;
2076+ return ;
2077+ }
2078+ if ( data . status >= 200 && data . status < 300 && requestUrl && ! isAccountsUrl ( requestUrl ) ) {
2079+ extendTokenExpiration ( ) ;
2080+ }
2081+ }
2082+
19552083// ============================================================================
19562084// Try It Out — Environment Variables
19572085// ============================================================================
@@ -2180,6 +2308,7 @@ async function loadXOriginValues(opId, paramName) {
21802308 } ) ;
21812309
21822310 var data = await resp . json ( ) ;
2311+ handleProxyResponse ( data , fullUrl ) ;
21832312
21842313 if ( btn ) {
21852314 btn . disabled = false ;
@@ -2380,6 +2509,7 @@ async function loadXOriginValuesForEnv(paramName) {
23802509 } ) ;
23812510
23822511 var data = await resp . json ( ) ;
2512+ handleProxyResponse ( data , fullUrl ) ;
23832513
23842514 if ( btn ) {
23852515 btn . disabled = false ;
@@ -3558,6 +3688,7 @@ async function sendRequest(opId, buttonEl) {
35583688 } )
35593689 } ) ;
35603690 var data = await resp . json ( ) ;
3691+ handleProxyResponse ( data , fullUrl ) ;
35613692
35623693 // Restore button
35633694 if ( buttonEl ) {
@@ -5500,6 +5631,7 @@ async function executePlaygroundStep(sid, buttonEl) {
55005631 } ) ;
55015632
55025633 var result = await resp . json ( ) ;
5634+ handleProxyResponse ( result , fullUrl ) ;
55035635
55045636 // Restore button
55055637 if ( buttonEl ) {
@@ -5641,6 +5773,9 @@ function canProceedToNextStep(skillSlug, currentStepIndex) {
56415773 var authMethod = sessionStorage . getItem ( 'anypoint_auth_method' ) || '' ;
56425774 if ( token && authMethod ) {
56435775 setAuthStatus ( true , null , authMethod ) ;
5776+ if ( sessionStorage . getItem ( 'anypoint_token_expires_at' ) ) {
5777+ startTtlTimer ( ) ;
5778+ }
56445779 }
56455780
56465781 // Render environment variables
@@ -6405,6 +6540,7 @@ async function runWorkflowStep(skillSlug, stepIndex) {
64056540 } )
64066541 } ) ;
64076542 var data = await resp . json ( ) ;
6543+ handleProxyResponse ( data , fullUrl ) ;
64086544
64096545 if ( spinner ) spinner . style . display = 'none' ;
64106546 if ( rightPanel ) rightPanel . setAttribute ( 'open' , '' ) ;
0 commit comments