Terms of Service enforcement is inconsistent between HTML and API requests
Summary
When Terms of Service enforcement is enabled, authenticated users experience inconsistent behavior depending on whether they access GitLab via HTML or API requests. HTML requests are properly redirected to the terms acceptance page, but API requests fail with generic errors without enforcing terms acceptance.
Problem Statement
Current Behavior:
- HTML requests from users who haven't accepted terms → Redirected to
/users/termspage ✓ - API requests from users who haven't accepted terms → Generic error responses (404, 500, etc.) ✗
- Scheduled pipelines owned by users who haven't accepted terms → Fail silently without clear messaging ✗
Expected Behavior:
- All authenticated requests (HTML and API) should enforce terms acceptance consistently
- Users should receive clear messaging about why their requests are blocked
- API requests should return a proper error response indicating terms acceptance is required
Impact
This bug causes:
- Broken automation - Scheduled pipelines and background jobs fail unexpectedly
- Poor UX - Users see generic errors instead of being told to accept terms
- Compliance bypass - Terms enforcement is partially bypassed for API requests
- Production disruptions - When ToS is updated and enforcement is enabled, existing automation breaks without clear cause
Affected Users
- Users with active API integrations
- Users with scheduled CI/CD pipelines
- Users with background jobs or webhooks
- SAML-authenticated users making API calls
Root Cause
The enforce_terms! before_action in ApplicationController only applies to HTML requests:
before_action :enforce_terms!, if: :should_enforce_terms?
def should_enforce_terms?
return false unless Gitlab::CurrentSettings.current_application_settings.enforce_terms
html_request? && !devise_controller? # <-- Only HTML requests!
end
The API layer (lib/api/api_guard.rb) has its own authentication system that doesn't check terms acceptance. The find_current_user! method validates:
- Token validity
- Access permissions
- Two-factor authentication
- But NOT terms acceptance
Steps to Reproduce
- Enable "All users must accept the Terms of Service and Privacy Policy to access GitLab" in Admin > Settings > General
- Create a new version of the terms
- As an existing user with an active web session, make an API request (e.g.,
GET /api/v4/user) - Observe: Request fails with generic error, no redirect to terms page
- Open a fresh/incognito session and log in
- Observe: User is properly redirected to terms acceptance page
Proposed Solution
Add terms acceptance check to the API authentication layer in lib/api/api_guard.rb:
def find_current_user!
user = find_user_from_sources
return unless user
# Check terms acceptance before other validations
if user.required_terms_not_accepted?
forbidden!(_("Please accept the Terms of Service before continuing."))
end
Gitlab::Auth::CurrentUserMode.bypass_session!(user.id) if bypass_session_for_admin_mode?(user)
unless api_access_allowed?(user)
forbidden!(api_access_denied_message(user))
end
# ... rest of method
end
This ensures:
- API requests enforce terms acceptance consistently with HTML requests
- Users receive clear error messaging
- Scheduled jobs and automation fail with proper error context
Related Issues
- Separate feature request needed: Grace period for Terms of Service enforcement to prevent production disruptions when ToS is updated
Acceptance Criteria
- API requests from users who haven't accepted terms return a 403 Forbidden with clear messaging
- Scheduled pipelines fail with clear error indicating terms acceptance is required
- HTML and API request behavior is consistent
- Error message clearly indicates user needs to accept terms
- Tests cover both HTML and API request scenarios
Edited by 🤖 GitLab Bot 🤖
