Skip to content

Add token refresh logic if the user's access token is expired#528

Merged
ShanChathusanda93 merged 1 commit into
asgardeo:mainfrom
ShanChathusanda93:refresh-call-issignedin-branch
Jun 8, 2026
Merged

Add token refresh logic if the user's access token is expired#528
ShanChathusanda93 merged 1 commit into
asgardeo:mainfrom
ShanChathusanda93:refresh-call-issignedin-branch

Conversation

@ShanChathusanda93

@ShanChathusanda93 ShanChathusanda93 commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

Purpose

Previously, isSignedIn in AuthenticationHelper returned false immediately when the access token was expired, causing the SPA-AUTH_CLIENT-VM-IV02 error to be thrown for any method that required authentication (e.g., after a long idle period where the SPAHelper timer was no longer active).

This fix attempts a silent token refresh via the browser's refreshAccessToken before returning false. If the refresh succeeds, isSignedIn returns true and the SPAHelper timer is re-armed. If the refresh fails, it returns false as before.

The fix is intentionally scoped to the browser layer (AuthenticationHelper) so it uses the browser-specific refresh flow without introducing network side effects into the base @asgardeo/javascript client's isSignedIn, which is a shared pure-check method.

Related Issues

  • N/A

Related PRs

  • N/A

Checklist

  • Followed the CONTRIBUTING guidelines.
  • Manual test round performed and verified.
  • Documentation provided. (Add links if there are any)
  • Unit tests provided. (Add links if there are any)

Security checks

Summary by CodeRabbit

  • Bug Fixes

    • More reliable signed-in detection: waits for ongoing token refreshes and triggers automatic refreshes so signed-in status reflects current authentication state.
  • Refactor

    • Internal authentication flow and messaging cleaned up for clearer, more robust behavior.
  • Chores

    • CI workflow updated to use the latest package manager version for linting.

@coderabbitai

coderabbitai Bot commented Jun 6, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@ShanChathusanda93, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 13 minutes and 10 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f8e5b5de-448b-4208-a757-c71f44da0c4e

📥 Commits

Reviewing files that changed from the base of the PR and between ffae447 and 76ca694.

📒 Files selected for processing (3)
  • .changeset/hot-wombats-lick.md
  • .github/workflows/pr-builder.yml
  • packages/browser/src/__legacy__/helpers/authentication-helper.ts
📝 Walkthrough

Walkthrough

isSignedIn() now returns true if already signed in, waits if a token refresh is underway, or attempts refreshAccessToken() and returns true on success or false on error; separately, the PR builder workflow changes the lint job's pnpm-version matrix entry from v10 to latest.

Changes

Token refresh handling

Layer / File(s) Summary
isSignedIn() wait-and-refresh logic
packages/browser/src/__legacy__/helpers/authentication-helper.ts
isSignedIn() returns true when the auth client reports signed-in; if _isTokenRefreshing is true it waits for the refresh to finish then re-checks; otherwise it sets _isTokenRefreshing, calls refreshAccessToken(), returns true on success or false on error, and resets the flag.

CI workflow matrix

Layer / File(s) Summary
lint job pnpm-version update
.github/workflows/pr-builder.yml
In the lint job strategy matrix, the pnpm-version value is changed from v10 to latest.

Sequence Diagram

sequenceDiagram
  participant Caller
  participant AuthClient
  participant TokenRefresher
  Caller->>AuthClient: isSignedIn()
  alt AuthClient signed in
    AuthClient-->>Caller: true
  else Token refresh in progress
    Caller->>TokenRefresher: await _isTokenRefreshing
    TokenRefresher-->>AuthClient: refresh completes
    AuthClient-->>Caller: isSignedIn() result
  else Not signed in and not refreshing
    Caller->>TokenRefresher: refreshAccessToken()
    alt refresh succeeds
      TokenRefresher-->>Caller: success -> return true
    else refresh throws
      TokenRefresher-->>Caller: error -> return false
    end
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested reviewers

  • KaveeshaPiumini

Poem

🐰 I nibble logs where tokens hide,
I hop in when the flags decide.
If one refresh runs, I wait my turn,
Otherwise I try — and leap or learn.
A carrot code, secure and spry.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: adding token refresh logic to the isSignedIn method when access tokens expire.
Description check ✅ Passed The description covers the purpose section well, explaining the problem and solution clearly. However, all checklist items remain unchecked, and no unit tests or documentation links are provided.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/browser/src/__legacy__/helpers/authentication-helper.ts`:
- Around line 708-719: The isSignedIn() method can trigger concurrent
refreshAccessToken() calls; modify isSignedIn() to reuse the same single-flight
coordination used in httpRequest() by consulting the _isTokenRefreshing
indicator (or the shared refresh promise) before starting a new refresh: if
_isTokenRefreshing is truthy await the existing refresh promise, otherwise
initiate refreshAccessToken() and set/clear the shared _isTokenRefreshing
promise/flag around it so parallel callers wait on the same promise and avoid
duplicate refreshes; keep existing behavior of returning true on successful
refresh and false on failure.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 26480d08-62c9-4604-b86a-ee8a37628682

📥 Commits

Reviewing files that changed from the base of the PR and between a3a8ab1 and 1c5dc9b.

📒 Files selected for processing (1)
  • packages/browser/src/__legacy__/helpers/authentication-helper.ts

Comment thread packages/browser/src/__legacy__/helpers/authentication-helper.ts
@ShanChathusanda93 ShanChathusanda93 force-pushed the refresh-call-issignedin-branch branch from 1c5dc9b to 3ed6e68 Compare June 6, 2026 18:55
Config,
} from '@asgardeo/javascript';
import {SPAHelper} from './spa-helper';
import { SPAHelper } from './spa-helper';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hope these changes are not intentional

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seeems lint failure is due to these unintentional formatting changes. let's revert these

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Install the Prettier VSCode extension. And format the document.

RP_IFRAME,
} from '../constants';
import {HttpClient} from '@asgardeo/javascript';
import { HttpClient } from '@asgardeo/javascript';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this too

Comment on lines +58 to +60
import { SPACustomGrantConfig } from '../models/request-custom-grant';
import { BrowserStorage } from '../models/storage';
import { SPAUtils } from '../utils';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and these as well

Comment on lines +709 to +731
if (await this._authenticationClient.isSignedIn()) {
return true;
}

// A refresh is already in progress — wait for it to finish then re-check.
if (this._isTokenRefreshing) {
await SPAUtils.until(() => !this._isTokenRefreshing);

return this._authenticationClient.isSignedIn();
}

// Token may be expired — attempt a silent refresh before giving up.
try {
this._isTokenRefreshing = true;
await this.refreshAccessToken();
this._isTokenRefreshing = false;

return true;
} catch {
this._isTokenRefreshing = false;

return false;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe we could use something like the following version to keep this._authenticationClient.isSignedIn method as the single source for determining the signed in status, instead of explicitly returning boolean status. (haven't tested the following myself though)

public async isSignedIn(): Promise<boolean> {
    if (await this._authenticationClient.isSignedIn()) {
        return this._authenticationClient.isSignedIn();
    }

    if (this._isTokenRefreshing) {
        await SPAUtils.until(() => !this._isTokenRefreshing);

        return this._authenticationClient.isSignedIn();
    }

    try {
        this._isTokenRefreshing = true;
        await this.refreshAccessToken();
    } catch {
        // Ignore refresh failures. Signed-in state is determined below.
    } finally {
        this._isTokenRefreshing = false;
    }

    return this._authenticationClient.isSignedIn();
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better to do this IMO. But +1 to merge the already tested path immediately and later bring this in.

@ShanChathusanda93 ShanChathusanda93 force-pushed the refresh-call-issignedin-branch branch 3 times, most recently from 5c73f0a to e1b2b25 Compare June 8, 2026 07:58
@ShanChathusanda93 ShanChathusanda93 force-pushed the refresh-call-issignedin-branch branch 3 times, most recently from 56a446c to 424b67a Compare June 8, 2026 09:05
@ShanChathusanda93 ShanChathusanda93 force-pushed the refresh-call-issignedin-branch branch from 424b67a to 76ca694 Compare June 8, 2026 09:24
@asgardeo-github-bot

Copy link
Copy Markdown

🦋 Changeset detected

The changes in this PR will be included in the next version bump.

Not sure what this means? Click here to learn what changesets are.

@ShanChathusanda93 ShanChathusanda93 merged commit 55b6bf5 into asgardeo:main Jun 8, 2026
6 of 9 checks passed
rksk added a commit to rksk/os-cs-tools that referenced this pull request Jun 9, 2026
…efresh fix)

Restores silent token refresh on access-token expiry (upstream
asgardeo/javascript#528). Before this, isSignedIn() returned false the moment
the access token expired, bouncing idle engineers to login; AuthGuard gates the
whole app on isSignedIn, so this degraded session stability.

No application code changes — the consumed SDK surface (AsgardeoProvider props,
useAsgardeo: isSignedIn/getAccessToken/getDecodedIdToken/signOut) is unchanged
across the jump; tsc build passes. Peer @asgardeo/react-router@2.0.0 (needs
>=0.15.0) still satisfied. Fixes #1885.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants