-
Notifications
You must be signed in to change notification settings - Fork 65
Fix infinite loop of refresh grant requests when the refresh token is expired or revoked #531
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| --- | ||
| '@asgardeo/browser': patch | ||
| '@asgardeo/react': patch | ||
| --- | ||
|
|
||
| Fix infinite loop of refresh grant requests when the refresh token is expired or revoked |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -388,6 +388,23 @@ const AsgardeoProvider: FC<PropsWithChildren<AsgardeoProviderProps>> = ({ | |
| }; | ||
| }, [asgardeo]); | ||
|
|
||
| // When the refresh token is expired or revoked, the browser SDK posts a | ||
| // 'refresh-access-token-error' message. Sync the React context so components | ||
| // stop calling auth methods and the user is redirected to sign in again. | ||
| useEffect(() => { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We may need to port this fix to other SDKs as well. @coderabbitai Create an issue in https://github.com/asgardeo/asgardeo to track this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
gh issue create \
--repo "asgardeo/asgardeo" \
--assignee "brionmario" \
--title "Port infinite refresh-token loop fix to other SDKs" \
--body "## Summary
When a refresh token is expired or revoked, certain Asgardeo SDKs enter an infinite loop of refresh-grant requests. A fix was implemented in the **JavaScript SDK** ([`@asgardeo/browser`](https://github.com/asgardeo/javascript/tree/main/packages/browser) and [`@asgardeo/react`](https://github.com/asgardeo/javascript/tree/main/packages/react)) via [asgardeo/javascript#531](https://github.com/asgardeo/javascript/pull/531). The same fix needs to be ported to all other Asgardeo SDKs.
## Root Cause
The \`isSignedIn()\` method attempts a refresh grant when the access token expires. The \`_isTokenRefreshing\` guard flag resets to \`false\` after each failure, causing every subsequent call to \`isSignedIn()\` (from navigation guards, polling intervals, \`_validateMethod\`, etc.) to fire new \`/token\` requests. Two additional factors contributed:
- The React context's \`isSignedInSync\` was never updated on refresh failure.
- \`scheduleAutoRefresh()\` called \`refreshAccessTokenAutomatically()\`, bypassing the guard mechanism.
## Fix Applied in JavaScript SDK
1. **authentication-helper.ts** – Added a \`_hasRefreshFailed\` boolean flag. After the first refresh failure in \`isSignedIn()\`, the flag is set to \`true\` and all subsequent calls return \`false\` immediately (no network requests). The flag resets to \`false\` on successful refresh or fresh sign-in via auth code exchange.
2. **spa-helper.ts** – Added a \`hasRefreshFailed()\` check in the immediate-refresh path of \`refreshAccessTokenAutomatically()\` to stop redundant attempts after \`isSignedIn()\` has marked the token as failed.
3. **AsgardeoProvider.tsx (React)** – Added a \`useEffect\` listener for the \`refresh-access-token-error\` window message. When received, sets \`isSignedInSync = false\` so React components stop treating the user as signed in.
## Action Required
Port equivalent logic to all other Asgardeo SDK packages, ensuring:
- [ ] A failure-tracking flag (or equivalent mechanism) prevents repeated refresh-grant requests after the first failure.
- [ ] The unauthenticated state is propagated correctly to framework-level context/providers.
- [ ] Normal refresh behavior resumes after a fresh sign-in.
## References
- Fix PR: [asgardeo/javascript#531](https://github.com/asgardeo/javascript/pull/531)
- Originating comment: https://github.com/asgardeo/javascript/pull/531#discussion_r3460381234
- Requested by: `@brionmario`
"Length of output: 3035 🏁 Script executed: #!/bin/bash
set -euo pipefail
gh issue create \
--repo "asgardeo/asgardeo" \
--title "Port infinite refresh-token loop fix to other SDKs" \
--body "## Summary
When a refresh token is expired or revoked, certain Asgardeo SDKs enter an infinite loop of refresh-grant requests. A fix was implemented in the **JavaScript SDK** ([`@asgardeo/browser`](https://github.com/asgardeo/javascript/tree/main/packages/browser) and [`@asgardeo/react`](https://github.com/asgardeo/javascript/tree/main/packages/react)) via [asgardeo/javascript#531](https://github.com/asgardeo/javascript/pull/531). The same fix needs to be ported to all other Asgardeo SDKs.
## Root Cause
The \`isSignedIn()\` method attempts a refresh grant when the access token expires. The \`_isTokenRefreshing\` guard flag resets to \`false\` after each failure, causing every subsequent call to \`isSignedIn()\` (from navigation guards, polling intervals, \`_validateMethod\`, etc.) to fire new \`/token\` requests. Two additional factors contributed:
- The React context's \`isSignedInSync\` was never updated on refresh failure.
- \`scheduleAutoRefresh()\` called \`refreshAccessTokenAutomatically()\`, bypassing the guard mechanism.
## Fix Applied in JavaScript SDK
1. **authentication-helper.ts** – Added a \`_hasRefreshFailed\` boolean flag. After the first refresh failure in \`isSignedIn()\`, the flag is set to \`true\` and all subsequent calls return \`false\` immediately (no network requests). The flag resets to \`false\` on successful refresh or fresh sign-in via auth code exchange.
2. **spa-helper.ts** – Added a \`hasRefreshFailed()\` check in the immediate-refresh path of \`refreshAccessTokenAutomatically()\` to stop redundant attempts after \`isSignedIn()\` has marked the token as failed.
3. **AsgardeoProvider.tsx (React)** – Added a \`useEffect\` listener for the \`refresh-access-token-error\` window message. When received, sets \`isSignedInSync = false\` so React components stop treating the user as signed in.
## Action Required
Port equivalent logic to all other Asgardeo SDK packages, ensuring:
- [ ] A failure-tracking flag (or equivalent mechanism) prevents repeated refresh-grant requests after the first failure.
- [ ] The unauthenticated state is propagated correctly to framework-level context/providers.
- [ ] Normal refresh behavior resumes after a fresh sign-in.
## References
- Fix PR: [asgardeo/javascript#531](https://github.com/asgardeo/javascript/pull/531)
- Originating comment: https://github.com/asgardeo/javascript/pull/531#discussion_r3460381234
- Requested by: `@brionmario`
"Length of output: 2778
It includes the root cause, a summary of all three changes from this PR, and acceptance criteria for the port. Note that I wasn't able to auto-assign it due to integration permissions — you may want to assign it manually from the issue page. |
||
| const handleRefreshTokenError = (event: MessageEvent): void => { | ||
| if (event?.data?.type === 'refresh-access-token-error') { | ||
| setIsSignedInSync(false); | ||
|
ShanChathusanda93 marked this conversation as resolved.
|
||
| } | ||
|
ShanChathusanda93 marked this conversation as resolved.
|
||
| }; | ||
|
|
||
| window.addEventListener('message', handleRefreshTokenError); | ||
|
|
||
| return (): void => { | ||
| window.removeEventListener('message', handleRefreshTokenError); | ||
| }; | ||
| }, []); | ||
|
|
||
| useEffect(() => { | ||
| (async (): Promise<void> => { | ||
| try { | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.