Following up on https://abp.io/support/questions/7373/Need-to-login-to-the-portal-even-after-the-tenant-activation-end-date-is-completed
This is a standard more realistic approach to the needs of SaaS and multitenancy.
Users need to be able to login even after an account has expired so they can re-up their payments.
What is the quickest way to implement this without having to put bad or incorrect data into the ActivationEndDate?
thanks, jasen
5 Answer(s)
-
0
To allow users to log in even after their tenant's subscription (ActivationEndDate) has expired—so they can renew or make payments—while still preventing access to the main application features, you can implement the following approach:
Customize Tenant Status Check:
- By default, ABP disables login for tenants whose
IsActive
isfalse
orActivationEndDate
is in the past. - You can override this behavior by customizing the tenant validation logic.
- By default, ABP disables login for tenants whose
Override TenantAvailabilityChecker:
- Create a custom implementation of
ITenantAvailabilityChecker
that allows login even if the tenant is expired, but restricts access to other features based on your business logic.
Example:
- Create a custom implementation of
public class CustomTenantAvailabilityChecker : DefaultTenantAvailabilityChecker { public CustomTenantAvailabilityChecker( ITenantRepository tenantRepository, IOptions<AbpTenantManagementOptions> options) : base(tenantRepository, options) { } public override async Task<TenantAvailabilityState> CheckAsync(string tenancyName) { var result = await base.CheckAsync(tenancyName); if (result == TenantAvailabilityState.InActive || result == TenantAvailabilityState.InActiveDueToEndDate) { // Allow login for expired tenants return TenantAvailabilityState.Available; } return result; } }
- Register your custom checker in the DI container in your module:
context.Services.Replace(ServiceDescriptor.Transient<ITenantAvailabilityChecker, CustomTenantAvailabilityChecker>());
Restrict Application Access After Login:
- After login, check the tenant's
ActivationEndDate
and, if expired, redirect users to a payment/renewal page instead of the main dashboard. - You can do this by adding a middleware or an authorization handler that checks the tenant's status on each request.
- After login, check the tenant's
Payment Flow:
- Use the SaaS and Payment modules to let users renew their subscription.
- After successful payment, update the tenant's
ActivationEndDate
and allow full access.
This approach ensures users can always log in to renew their subscription, but cannot use the main application until payment is made.
Sources:
This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.
-
0
hi
The quickest way is not to set
ActivationEndDate
.Its purpose is to limit the tenant, if you don't need it, you can ignore it.
Thanks.
-
0
Ok, so I gotta raise a bit of a red flag here, sorry.
Both ActivationEndDate and EditionEndDate currently disable login
Payments module sets the ActivationEndDate to the subscription automatically.
In the real world, when subscriptions end, SaaS providers need customers to be able to login and update payment methods.
The obvious conclusion would be that ActivationEndDate should just be describing the state of the subscription and not prohibiting login.
Instead, you are telling us we need to, after payments come in, create our own hook on that event, copy the ActivationEndDate to a custom property or setting somewhere, the empty out ActivationEndDate?
I'll have to do this because time is of the essense, but it's really illogical. Especially given there doesn't seem to be much different between the two existing properties.
-
0
hi
We will review this feature again.
Thanks.
-
0
Short answer: Login is controlled by tenant activation state, not by subscription/edition expiry. Keep the tenant
ActivationState
as Active and do not useActivationEndDate
for subscription purposes. Subscription expiry is tracked withEditionEndDateUtc
, which disables edition-based features but does not block login.What the code does
- Login availability uses ActivationState/ActivationEndDate
public virtual Task<bool> IsActiveAsync(Tenant tenant) { return Task.FromResult(tenant.ActivationState switch { TenantActivationState.Active => true, TenantActivationState.Passive => false, TenantActivationState.ActiveWithLimitedTime => tenant.ActivationEndDate >= Clock.Now, _ => false }); }
This value is used when populating
TenantConfiguration.IsActive
in theTenantStore
, which in turn controls tenant availability for login resolution.- Subscription expiry is stored in EditionEndDateUtc
tenant.EditionEndDateUtc = eventData.PeriodEndDate; tenant.EditionId = Guid.Parse(eventData.ExtraProperties[EditionConsts.EditionIdParameterName]?.ToString());
if (tenant.EditionEndDateUtc <= DateTime.UtcNow) { tenant.EditionId = null; }
- Expired edition removes the edition claim, not the login
var tenant = await tenantRepository.FindAsync(currentTenant.Id.Value); if (tenant?.GetActiveEditionId() != null) { identity.AddOrReplace(new Claim(AbpClaimTypes.EditionId, tenant.GetActiveEditionId().ToString())); }
public virtual Guid? GetActiveEditionId() { if (!EditionEndDateUtc.HasValue) { return EditionId; } if (EditionEndDateUtc >= DateTime.UtcNow) { return EditionId; } return null; }
Practical guidance
To allow login after subscription ends: Leave the tenant
ActivationState
asActive
(or avoid usingActiveWithLimitedTime
/ActivationEndDate
for subscription timing). Let the subscription simply expire viaEditionEndDateUtc
. Users can still log in but won’t have the edition claim/benefits until renewal.To guide users to renew after login: Add a small middleware/authorization handler that checks
GetActiveEditionId()
(or the presence of the edition claim) and redirects to a renewal page when it is null.Only if you must allow login for expired ActivationEndDate: Either set the tenant back to
Active
or customize the activation evaluation (advanced: replaceTenantManager.IsActiveAsync
logic), but this is discouraged for subscription logic. Prefer keeping activation for administrative suspension only.
Conclusion
- You do not need to touch
ActivationEndDate
for subscriptions. UsingEditionEndDateUtc
already allows login after expiry and prevents edition features until payment is renewed.