diff --git a/src/OpenIddict.Core/Managers/OpenIddictAuthorizationManager.cs b/src/OpenIddict.Core/Managers/OpenIddictAuthorizationManager.cs
index c3fbc1d1..b43f7049 100644
--- a/src/OpenIddict.Core/Managers/OpenIddictAuthorizationManager.cs
+++ b/src/OpenIddict.Core/Managers/OpenIddictAuthorizationManager.cs
@@ -338,6 +338,22 @@ namespace OpenIddict.Core
return Store.ListAsync(query, cancellationToken);
}
+ ///
+ /// Lists the ad-hoc authorizations that are marked as invalid or have no
+ /// valid token attached and that can be safely removed from the database.
+ ///
+ /// The number of results to return.
+ /// The number of results to skip.
+ /// The that can be used to abort the operation.
+ ///
+ /// A that can be used to monitor the asynchronous operation,
+ /// whose result returns all the elements returned when executing the specified query.
+ ///
+ public virtual Task> ListInvalidAsync([CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken)
+ {
+ return Store.ListInvalidAsync(count, offset, cancellationToken);
+ }
+
///
/// Revokes an authorization.
///
diff --git a/src/OpenIddict.Core/Managers/OpenIddictTokenManager.cs b/src/OpenIddict.Core/Managers/OpenIddictTokenManager.cs
index 0d9f852d..ea012aa1 100644
--- a/src/OpenIddict.Core/Managers/OpenIddictTokenManager.cs
+++ b/src/OpenIddict.Core/Managers/OpenIddictTokenManager.cs
@@ -490,6 +490,22 @@ namespace OpenIddict.Core
return Store.ListAsync(query, cancellationToken);
}
+ ///
+ /// Lists the tokens that are marked as expired or invalid
+ /// and that can be safely removed from the database.
+ ///
+ /// The number of results to return.
+ /// The number of results to skip.
+ /// The that can be used to abort the operation.
+ ///
+ /// A that can be used to monitor the asynchronous operation,
+ /// whose result returns all the elements returned when executing the specified query.
+ ///
+ public virtual Task> ListInvalidAsync([CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken)
+ {
+ return Store.ListInvalidAsync(count, offset, cancellationToken);
+ }
+
///
/// Redeems a token.
///
diff --git a/src/OpenIddict.Core/Stores/IOpenIddictAuthorizationStore.cs b/src/OpenIddict.Core/Stores/IOpenIddictAuthorizationStore.cs
index 6ce29b16..09bee76f 100644
--- a/src/OpenIddict.Core/Stores/IOpenIddictAuthorizationStore.cs
+++ b/src/OpenIddict.Core/Stores/IOpenIddictAuthorizationStore.cs
@@ -174,6 +174,19 @@ namespace OpenIddict.Core
///
Task> ListAsync([NotNull] Func, IQueryable> query, CancellationToken cancellationToken);
+ ///
+ /// Lists the ad-hoc authorizations that are marked as invalid or have no
+ /// valid token attached and that can be safely removed from the database.
+ ///
+ /// The number of results to return.
+ /// The number of results to skip.
+ /// The that can be used to abort the operation.
+ ///
+ /// A that can be used to monitor the asynchronous operation,
+ /// whose result returns all the elements returned when executing the specified query.
+ ///
+ Task> ListInvalidAsync([CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken);
+
///
/// Sets the status associated with an authorization.
///
diff --git a/src/OpenIddict.Core/Stores/IOpenIddictTokenStore.cs b/src/OpenIddict.Core/Stores/IOpenIddictTokenStore.cs
index b5ed0a47..91d09f81 100644
--- a/src/OpenIddict.Core/Stores/IOpenIddictTokenStore.cs
+++ b/src/OpenIddict.Core/Stores/IOpenIddictTokenStore.cs
@@ -248,6 +248,19 @@ namespace OpenIddict.Core
///
Task> ListAsync([NotNull] Func, IQueryable> query, CancellationToken cancellationToken);
+ ///
+ /// Lists the tokens that are marked as expired or invalid
+ /// and that can be safely removed from the database.
+ ///
+ /// The number of results to return.
+ /// The number of results to skip.
+ /// The that can be used to abort the operation.
+ ///
+ /// A that can be used to monitor the asynchronous operation,
+ /// whose result returns all the elements returned when executing the specified query.
+ ///
+ Task> ListInvalidAsync([CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken);
+
///
/// Sets the authorization associated with a token.
///
diff --git a/src/OpenIddict.Core/Stores/OpenIddictAuthorizationStore.cs b/src/OpenIddict.Core/Stores/OpenIddictAuthorizationStore.cs
index 1975bbac..d272f4ca 100644
--- a/src/OpenIddict.Core/Stores/OpenIddictAuthorizationStore.cs
+++ b/src/OpenIddict.Core/Stores/OpenIddictAuthorizationStore.cs
@@ -263,6 +263,44 @@ namespace OpenIddict.Core
///
public abstract Task> ListAsync([NotNull] Func, IQueryable> query, CancellationToken cancellationToken);
+ ///
+ /// Lists the ad-hoc authorizations that are marked as invalid or have no
+ /// valid token attached and that can be safely removed from the database.
+ ///
+ /// The number of results to return.
+ /// The number of results to skip.
+ /// The that can be used to abort the operation.
+ ///
+ /// A that can be used to monitor the asynchronous operation,
+ /// whose result returns all the elements returned when executing the specified query.
+ ///
+ public virtual Task> ListInvalidAsync([CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken)
+ {
+ IQueryable Query(IQueryable authorizations)
+ {
+ var query = (from authorization in authorizations
+ where authorization.Status != OpenIddictConstants.Statuses.Valid ||
+ (authorization.Type == OpenIddictConstants.AuthorizationTypes.AdHoc &&
+ !authorization.Tokens.Any(token => token.Status == OpenIddictConstants.Statuses.Valid))
+ orderby authorization.Id
+ select authorization).AsQueryable();
+
+ if (offset.HasValue)
+ {
+ query = query.Skip(offset.Value);
+ }
+
+ if (count.HasValue)
+ {
+ query = query.Take(count.Value);
+ }
+
+ return query;
+ }
+
+ return ListAsync(Query, cancellationToken);
+ }
+
///
/// Sets the status associated with an authorization.
///
diff --git a/src/OpenIddict.Core/Stores/OpenIddictTokenStore.cs b/src/OpenIddict.Core/Stores/OpenIddictTokenStore.cs
index 992cbfeb..80584071 100644
--- a/src/OpenIddict.Core/Stores/OpenIddictTokenStore.cs
+++ b/src/OpenIddict.Core/Stores/OpenIddictTokenStore.cs
@@ -399,6 +399,43 @@ namespace OpenIddict.Core
///
public abstract Task> ListAsync([NotNull] Func, IQueryable> query, CancellationToken cancellationToken);
+ ///
+ /// Lists the tokens that are marked as expired or invalid
+ /// and that can be safely removed from the database.
+ ///
+ /// The number of results to return.
+ /// The number of results to skip.
+ /// The that can be used to abort the operation.
+ ///
+ /// A that can be used to monitor the asynchronous operation,
+ /// whose result returns all the elements returned when executing the specified query.
+ ///
+ public virtual Task> ListInvalidAsync([CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken)
+ {
+ IQueryable Query(IQueryable tokens)
+ {
+ var query = (from token in tokens
+ where token.ExpirationDate < DateTimeOffset.UtcNow ||
+ token.Status != OpenIddictConstants.Statuses.Valid
+ orderby token.Id
+ select token).AsQueryable();
+
+ if (offset.HasValue)
+ {
+ query = query.Skip(offset.Value);
+ }
+
+ if (count.HasValue)
+ {
+ query = query.Take(count.Value);
+ }
+
+ return query;
+ }
+
+ return ListAsync(Query, cancellationToken);
+ }
+
///
/// Sets the authorization associated with a token.
///