refresh method

Future<OAuthSession> refresh(
  1. OAuthSession session
)

Refreshes session using the DPoP-bound refresh token flow.

The authorization server is re-discovered from OAuthSession.issuer. The DPoP key pair from the session is reused. The given session is never mutated; a brand-new OAuthSession is returned and stored.

If the server rejects the refresh token with invalid_grant, the session is deleted from the OAuthSessionStore and an OAuthSessionRevokedException is thrown so callers can route the user back through authorize — unless the store has already rotated past the token this call tried, in which case the rejection says only that the tried token was spent and the current stored session is returned instead.

Throws:

Implementation

Future<OAuthSession> refresh(final OAuthSession session) async {
  final refreshToken = session.refreshToken;
  if (refreshToken == null || refreshToken.isEmpty) {
    throw OAuthException('No refresh token available');
  }

  // Single-flight: coalesce concurrent refreshes of the same account onto
  // one shared future so the rotating refresh token is POSTed exactly once.
  final inFlight = _inFlightRefreshes[session.sub];
  if (inFlight != null) return inFlight;

  final future = _refresh(session, refreshToken);
  _inFlightRefreshes[session.sub] = future;
  try {
    return await future;
  } finally {
    _inFlightRefreshes.remove(session.sub);
  }
}