refresh method Null safety

Future<AuthToken> refresh(
  1. String? refreshToken,
  2. String? clientID,
  3. String? clientSecret,
  4. {List<AuthScope>? requestedScopes}
)

Refreshes a valid AuthToken instance.

This method will refresh a AuthToken given the AuthToken's refreshToken for a given client ID. This method coordinates with this instance's delegate to update the old token with a new access token and issue/expiration dates if successful. If not successful, it will throw an AuthRequestError.

Implementation

Future<AuthToken> refresh(
  String? refreshToken,
  String? clientID,
  String? clientSecret, {
  List<AuthScope>? requestedScopes,
}) async {
  if (clientID == null) {
    throw AuthServerException(AuthRequestError.invalidClient, null);
  }

  final client = await getClient(clientID);
  if (client == null) {
    throw AuthServerException(AuthRequestError.invalidClient, null);
  }

  if (refreshToken == null) {
    throw AuthServerException(AuthRequestError.invalidRequest, client);
  }

  final t = await delegate.getToken(this, byRefreshToken: refreshToken);
  if (t == null || t.clientID != clientID) {
    throw AuthServerException(AuthRequestError.invalidGrant, client);
  }

  if (clientSecret == null) {
    throw AuthServerException(AuthRequestError.invalidClient, client);
  }

  if (client.hashedSecret != hashPassword(clientSecret, client.salt!)) {
    throw AuthServerException(AuthRequestError.invalidClient, client);
  }

  var updatedScopes = t.scopes;
  if ((requestedScopes?.length ?? 0) != 0) {
    // If we do specify scope
    for (final incomingScope in requestedScopes!) {
      final hasExistingScopeOrSuperset = t.scopes!.any(
        (existingScope) => incomingScope.isSubsetOrEqualTo(existingScope),
      );

      if (!hasExistingScopeOrSuperset) {
        throw AuthServerException(AuthRequestError.invalidScope, client);
      }

      if (!client.allowsScope(incomingScope)) {
        throw AuthServerException(AuthRequestError.invalidScope, client);
      }
    }

    updatedScopes = requestedScopes;
  } else if (client.supportsScopes) {
    // Ensure we still have access to same scopes if we didn't specify any
    for (final incomingScope in t.scopes!) {
      if (!client.allowsScope(incomingScope)) {
        throw AuthServerException(AuthRequestError.invalidScope, client);
      }
    }
  }

  final diff = t.expirationDate!.difference(t.issueDate!);
  final now = DateTime.now().toUtc();
  final newToken = AuthToken()
    ..accessToken = randomStringOfLength(32)
    ..issueDate = now
    ..expirationDate = now.add(Duration(seconds: diff.inSeconds)).toUtc()
    ..refreshToken = t.refreshToken
    ..type = t.type
    ..scopes = updatedScopes
    ..resourceOwnerIdentifier = t.resourceOwnerIdentifier
    ..clientID = t.clientID;

  await delegate.updateToken(
    this,
    t.accessToken,
    newToken.accessToken,
    newToken.issueDate,
    newToken.expirationDate,
  );

  return newToken;
}