Open Closed

Allowing login after subscription expires #9752


User avatar
0
jasenfici@gmail.com created

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)
  • User Avatar
    0
    AI-Bot created
    Support Team ABP Agent

    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:

    1. Customize Tenant Status Check:

      • By default, ABP disables login for tenants whose IsActive is false or ActivationEndDate is in the past.
      • You can override this behavior by customizing the tenant validation logic.
    2. 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:

    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>());
    
    1. 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.
    2. 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.

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    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.

  • User Avatar
    0
    jasenfici@gmail.com created

    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.

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    We will review this feature again.

    Thanks.

  • User Avatar
    0
    enisn created
    Support Team .NET Developer

    Short answer: Login is controlled by tenant activation state, not by subscription/edition expiry. Keep the tenant ActivationState as Active and do not use ActivationEndDate for subscription purposes. Subscription expiry is tracked with EditionEndDateUtc, 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 the TenantStore, 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 as Active (or avoid using ActiveWithLimitedTime/ActivationEndDate for subscription timing). Let the subscription simply expire via EditionEndDateUtc. 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: replace TenantManager.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. Using EditionEndDateUtc already allows login after expiry and prevents edition features until payment is renewed.
Boost Your Development
ABP Live Training
Packages
See Trainings
Mastering ABP Framework Book
The Official Guide
Mastering
ABP Framework
Learn More
Mastering ABP Framework Book
Made with ❤️ on ABP v10.0.0-preview. Updated on September 01, 2025, 08:37