withAuth<T> method

Future<T> withAuth<T>(
  1. Future<T> call(), {
  2. List<PortalServiceCode> sso = const [],
})

Executes call with automatic re-authentication on session expiry.

If sso is provided, ensures SSO sessions are established for the listed services before calling call. SSO state is cached per service and only re-established when the portal session is refreshed.

If call fails with a non-DioException error (indicating session expiry or auth failure), this method re-authenticates using stored credentials, re-establishes SSO sessions, and retries call once.

Throws NotLoggedInException if no stored credentials are available. Rethrows LoginException if re-authentication is rejected (wrong credentials, account locked, password expired, etc.). Rethrows DioException from call or re-auth (network errors).

Implementation

Future<T> withAuth<T>(
  Future<T> Function() call, {
  List<PortalServiceCode> sso = const [],
}) async {
  try {
    await _ensureSso(sso);
    final result = await call();
    _onAuthStatusChanged(.authenticated);
    return result;
  } on DioException {
    _onAuthStatusChanged(.offline);
    rethrow;
  } catch (_) {
    final username = await _secureStorage.read(key: _usernameKey);
    final password = await _secureStorage.read(key: _passwordKey);
    if (username == null || password == null) {
      _onAuthStatusChanged(.unauthenticated);
      throw NotLoggedInException();
    }

    try {
      await _portalService.login(username, password);
    } on DioException {
      _onAuthStatusChanged(.offline);
      rethrow;
    } on LoginException {
      await _clearCredentials();
      _onAuthStatusChanged(.unauthenticated);
      rethrow;
    }

    _ssoCache.clear();
    try {
      await _ensureSso(sso);
      final result = await call();
      _onAuthStatusChanged(.authenticated);
      return result;
    } on DioException {
      _onAuthStatusChanged(.offline);
      rethrow;
    }
  }
}