@@ -77,6 +77,41 @@ export class RedirectRequestHandler extends AuthorizationRequestHandler {
7777 } ) ;
7878 }
7979
80+ /**
81+ * Cleanup all stale authorization requests and configurations from storage.
82+ * This scans localStorage for any keys matching the appauth patterns and removes them,
83+ * including the authorization request handle key.
84+ */
85+ public cleanupStaleAuthorizationData ( ) : Promise < void > {
86+ // Check if we're in a browser environment with localStorage
87+ if ( typeof window === 'undefined' || ! window . localStorage ) {
88+ return Promise . resolve ( ) ;
89+ }
90+
91+ const keysToRemove : string [ ] = [ ] ;
92+
93+ // Scan localStorage for all appauth-related keys
94+ for ( let i = 0 ; i < window . localStorage . length ; i ++ ) {
95+ const key = window . localStorage . key ( i ) ;
96+ if (
97+ key &&
98+ ( key . includes ( '_appauth_authorization_request' ) ||
99+ key . includes ( '_appauth_authorization_service_configuration' ) ||
100+ key === AUTHORIZATION_REQUEST_HANDLE_KEY )
101+ ) {
102+ keysToRemove . push ( key ) ;
103+ }
104+ }
105+
106+ // Remove all found stale keys
107+ const removePromises = keysToRemove . map ( ( key ) => this . storageBackend . removeItem ( key ) ) ;
108+ return Promise . all ( removePromises ) . then ( ( ) => {
109+ if ( keysToRemove . length > 0 ) {
110+ log ( `Cleaned up ${ keysToRemove . length } stale authorization data entries` ) ;
111+ }
112+ } ) ;
113+ }
114+
80115 /**
81116 * Attempts to introspect the contents of storage backend and completes the
82117 * request.
@@ -119,12 +154,8 @@ export class RedirectRequestHandler extends AuthorizationRequestHandler {
119154 } else {
120155 authorizationResponse = new AuthorizationResponse ( { code : code , state : state } ) ;
121156 }
122- // cleanup state
123- return Promise . all ( [
124- this . storageBackend . removeItem ( AUTHORIZATION_REQUEST_HANDLE_KEY ) ,
125- this . storageBackend . removeItem ( authorizationRequestKey ( handle ) ) ,
126- this . storageBackend . removeItem ( authorizationServiceConfigurationKey ( handle ) ) ,
127- ] ) . then ( ( ) => {
157+ // cleanup all authorization data including current and stale entries
158+ return this . cleanupStaleAuthorizationData ( ) . then ( ( ) => {
128159 log ( 'Delivering authorization response' ) ;
129160 return {
130161 request : request ,
@@ -134,7 +165,10 @@ export class RedirectRequestHandler extends AuthorizationRequestHandler {
134165 } ) ;
135166 } else {
136167 log ( 'Mismatched request (state and request_uri) dont match.' ) ;
137- return Promise . resolve ( null ) ;
168+ // cleanup all authorization data even on mismatch to prevent stale PKCE data
169+ return this . cleanupStaleAuthorizationData ( ) . then ( ( ) => {
170+ return null ;
171+ } ) ;
138172 }
139173 } )
140174 ) ;
0 commit comments