Two more fixes from the device-flow security review: slow_down interval grew without bound (OidcController): - Each too-fast poll bumped the persisted interval by 5s with no ceiling, so a client polling slightly fast — or an attacker spamming a known device_code — could balloon it (5→10→15→…) past the 10-minute expiry and starve a legitimate client of its token. Clamp the bump to OidcDeviceCode::MAX_INTERVAL (30s); a client polling at the advertised interval is never throttled. Expired device codes accumulated forever (OidcTokenCleanupJob): - Anonymous callers can create device codes via /oauth/device_authorization, and expired/denied/abandoned rows were never reaped. Sweep rows past expiry (with a 1-hour grace to stay clear of in-flight redemption); redeemed codes are already destroyed at token issuance. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016Q4ATZHoMCWqvSpE2yYoie
40 lines
2.2 KiB
Ruby
40 lines
2.2 KiB
Ruby
class OidcTokenCleanupJob < ApplicationJob
|
|
queue_as :default
|
|
|
|
def perform
|
|
# Delete expired access tokens (keep revoked ones for audit trail)
|
|
expired_access_tokens = OidcAccessToken.where("expires_at < ?", 7.days.ago)
|
|
deleted_count = expired_access_tokens.delete_all
|
|
Rails.logger.info "OIDC Token Cleanup: Deleted #{deleted_count} expired access tokens"
|
|
|
|
# Delete expired refresh tokens (keep revoked ones for audit trail)
|
|
expired_refresh_tokens = OidcRefreshToken.where("expires_at < ?", 7.days.ago)
|
|
deleted_count = expired_refresh_tokens.delete_all
|
|
Rails.logger.info "OIDC Token Cleanup: Deleted #{deleted_count} expired refresh tokens"
|
|
|
|
# Delete old revoked tokens (after 30 days for audit trail)
|
|
old_revoked_access_tokens = OidcAccessToken.where("revoked_at < ?", 30.days.ago)
|
|
deleted_count = old_revoked_access_tokens.delete_all
|
|
Rails.logger.info "OIDC Token Cleanup: Deleted #{deleted_count} old revoked access tokens"
|
|
|
|
old_revoked_refresh_tokens = OidcRefreshToken.where("revoked_at < ?", 30.days.ago)
|
|
deleted_count = old_revoked_refresh_tokens.delete_all
|
|
Rails.logger.info "OIDC Token Cleanup: Deleted #{deleted_count} old revoked refresh tokens"
|
|
|
|
# Delete old used authorization codes (after 7 days)
|
|
old_auth_codes = OidcAuthorizationCode.where("created_at < ?", 7.days.ago)
|
|
deleted_count = old_auth_codes.delete_all
|
|
Rails.logger.info "OIDC Token Cleanup: Deleted #{deleted_count} old authorization codes"
|
|
|
|
# Delete expired device codes (RFC 8628). They have a ~10 minute TTL and no
|
|
# audit value; a redeemed code is already destroyed at token issuance. Once
|
|
# expired a code can never be redeemed, so this single expiry sweep clears the
|
|
# expired, denied, and abandoned rows that would otherwise accumulate forever
|
|
# (anonymous callers can create them via /oauth/device_authorization). The
|
|
# short grace keeps this clear of any in-flight redemption near expiry.
|
|
expired_device_codes = OidcDeviceCode.where("expires_at < ?", 1.hour.ago)
|
|
deleted_count = expired_device_codes.delete_all
|
|
Rails.logger.info "OIDC Token Cleanup: Deleted #{deleted_count} expired device codes"
|
|
end
|
|
end
|