Files
outline/server/queues/tasks/CleanupDynamicOAuthClientsTask.ts
Tom Moor 957648a588 feat: OAuth dynamic client registration (#11462)
* feat: DCR first pass

* Add cleanup task, management endpoints

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* wip

* Combine migrations

* Self review

* fix: Guard OAuth policies

* fix: Application access list not updating on deletion

* feat: Add OAUTH_DISABLE_DCR env var to disable dynamic client registration

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: Validate max length of redirect URIs in DCR schemas

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Self review

* Use withCtx methods for correct event creation

* Remove incorrect scopes_supported

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 17:30:19 -05:00

59 lines
1.5 KiB
TypeScript

import { subDays, subHours } from "date-fns";
import { Op } from "sequelize";
import Logger from "@server/logging/Logger";
import { OAuthClient } from "@server/models";
import { TaskPriority } from "./base/BaseTask";
import type { Props } from "./base/CronTask";
import { CronTask, TaskInterval } from "./base/CronTask";
/**
* Deletes dynamically registered OAuth clients (createdById is null) that are
* either never used (lastActiveAt is null) after 48 hours, or that have been
* used but inactive for 30 days.
*/
export default class CleanupDynamicOAuthClientsTask extends CronTask {
public async perform({ limit }: Props) {
const now = new Date();
const neverUsedCutoff = subHours(now, 48);
const inactiveCutoff = subDays(now, 30);
const count = await OAuthClient.unscoped().destroy({
where: {
createdById: null,
[Op.or]: [
{
// Never used and created more than 48 hours ago.
lastActiveAt: null,
createdAt: { [Op.lt]: neverUsedCutoff },
},
{
// Used but inactive for more than 30 days.
lastActiveAt: { [Op.lt]: inactiveCutoff },
},
],
},
limit,
force: true,
});
if (count > 0) {
Logger.info("task", `Deleted dynamic OAuth clients`, {
count,
});
}
}
public get cron() {
return {
interval: TaskInterval.Day,
};
}
public get options() {
return {
attempts: 1,
priority: TaskPriority.Background,
};
}
}