Is it possible to set an expiration date for user accounts?

AI-generated summary

Willy initiates the discussion by asking if Discourse supports setting expiration dates for user accounts registered via invitation links, specifically requesting a mechanism to enforce membership renewals after a set period. The consensus among experienced developers is that this functionality is not native to Discourse and requires custom development. pfaffman suggests a common approach: adding new users to a specific group upon signup and then using a plugin to remove them from that group after a time limit, potentially tracking the deadline using a user custom field.

When Willy asks which existing plugin to use, pfaffman clarifies that no such plugin currently exists. However, they outline two potential implementation paths: developing a custom plugin or using a low-code approach combining the Data Explorer plugin with external automation tools (like Zapier or GitHub Actions) to trigger group removals. tobiaseigen supports this, noting it would be a great candidate for a new automation script or plugin contribution. As Willy considers building a solution with additional key-value metadata features, tobiaseigen moves the thread to the Development category, emphasizing that Willy should focus on building the prototype first rather than worrying about core integration filters immediately. It is confirmed that invitation links are always unique.

Finally, pfaffman shares a concrete Ruby code snippet from a plugin they wrote, demonstrating how to implement a scheduled job (RemoveExpiredFreeMonthMembers) that runs daily to delete GroupUser records older than one month. This provides a direct technical reference for achieving the desired expiration logic. The thread concludes with a reminder that complex custom features are best handled through plugins or marketplaces rather than direct core modifications.

Every time a user registers with an invitation link, I would like that account to only last x months and once the deadline has reached the user must renew their account, is it possible to do so?

It is basically a membership with an expiration date and renewal. If this feature does not exist in Discourse, is it possible to program it through a plugin or something similar without touching the core? or is there no support in the API and webhooks for something like this?

You’d add them to a group when they joined. You’d then have a plugin that removed them from the group after the time limit was up. Just how you’d keep up with the month isn’t clear. Probably a user custom field with the end date would be the most simple.

“You’d then have a plugin that removed them from the group after the time limit was up.” which plugin?

“Probably a user custom field with the end date would be the most simple.” Do I add that information during signup? Then I should use a webhook at that point, correct?

There is no such plugin. Someone would need to write it.

No. The plugin would do that. And it’s likely that there’s a way to discern when they got added via the database and data explorer, though I’m not really sure.

If you’re not self hosted, or for other reason don’t want a plugin,
It might also be possible to hack something together using the data explorer plugin (to get data on when they were added and hence, should be deleted) and use an automation/api tool (like zapier, though I’ve also used github actions) to remove them from the group when the time comes.

This would be a nice candidate for an automation script! Does not exist yet so you could contribute it or hire someone to do it for you and contribute it, in Marketplace.

I can do that, but with an extra feature: it should allow key-value fields to be added.

The idea is that I can associate information with an invitation link with the information I want. The values can be a simple string or a JSON, and each key is a column in the database. Then, when the user finishes registering, an extra key-value pair is added, which is their username.

My question is, will it pass your filters and be added to the native Discourse source code? And this leads me to an additional question, are invitation links always unique?

I slipped this topic across to Development because we are moving out of support territory here. You need to just get going with creating the plugin or automation that does what you want. Let us know how you get on! If the features you add are more widely useful, they may be considered for inclusion eventually in core Discourse.

Refer to Documentation > Developer Guides and #community-wiki:developers for guidance on creating plugins.

You can also start more topics in Development to ask more questions, but I do recommend you have code to share as you do so. It is easier for others to help you if they can see what you’ve done so far.

Yes, invitation links are always unique.

I don’t know what you mean by “pass your filters and be added to the native Discourse source code”.

These are the types of questions I think you will be able to find out for yourself as you dig into the code.

did you ever get this idea to work?

I’ve implemented it in a plugin that I wrote to support https://www.refrunner.com/. Something like this:

# frozen_string_literal: true

module Jobs
  class RemoveExpiredFreeMonthMembers < ::Jobs::Scheduled
    every 1.day

    def execute(args)
      return unless SiteSetting.discourse_citationwizard_enabled
      group_id = SiteSetting.citation_wizard_free_month_group.to_i
      return if group_id <= 0

      GroupUser
        .where(group_id: group_id)
        .where("user_id > 0")
        .where("created_at < ?", 1.month.ago)
        .delete_all
    end
  end
end

If that’s not enough for you to solve it you can post in Marketplace and/or contact me.