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 AuthClient? client = await getClient(clientID);
  if (client == null) {
    throw AuthServerException(AuthRequestError.invalidClient, null);
  }

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

  final AuthToken? 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 (var 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 (var 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;
}