Emit audit events on IAM consent accept and reject

What does this MR do and why?

Adds GitLab audit events when a user accepts or rejects an IAM consent challenge, replacing the deferred TODO markers in the IAM consent services. The event shape mirrors the existing Doorkeeper precedent in Oauth::AuthorizationsController#audit_oauth_authorization, adapted for multi-cell safety.

Two new audit event types are introduced:

  • user_authorized_iam_oauth_application
  • user_rejected_iam_oauth_application

Important: target could be the application, similar to the existing audit_oauth_authorization but in multi-cell environment the oauth_application might not be available in the current cell, so we avoid to fetch it.

Event shape

  • scope, target: @user: multi-cell-safe. The OAuth application is managed by the external IAM service and is not guaranteed to exist in the current Rails cell, so we deliberately diverge from the Doorkeeper precedent (which uses target: application).
  • target_details: client_name (human-readable application name). Admins see the application name in the Target column of the Audit events table without inspecting the JSON payload. The resulting target_type: "User" / target_details: "<app name>" mismatch is visible in GraphQL and CSV export but acceptable: no code resolves target_type: "User" back to a record for audit events, no admin filtering by target_type exists, and the UI only displays target_details.
  • additional_details:
    • application_id — the IAM-issued OAuth client id
    • application_name — same as target_details, kept for structured access
    • scopes — the OAuth application's registered scopes (from client.scopes in the IAM consent challenge response)
    • requested_scopes — scopes requested for this consent
    • granted_scopes — scopes actually granted (equals requested_scopes on accept, [] on reject)
    • user_agent — captured from request.user_agent (security request)
  • ip_address: request.remote_ip.

Design decisions

  • Distinct event names from the legacy Doorkeeper flow. The trust boundary differs (external IAM service versus an in-Rails Doorkeeper application) and there is no legacy reject equivalent to reuse.
  • scope and target: @user. Multi-cell-safe. No dependency on the OAuth application existing in the local Rails database. Discussed in MR comment.
  • target_details is the client_name. Mild duplication with additional_details.application_name is intentional: the former is denormalized for table display, the latter retains structured access. Same pattern used by other GitLab audit events.
  • feature_category: authorization. Aligns with the existing user_authorized_oauth_application.yml and oauth_application_created.yml.

References

Screenshots

image

How to set up and validate locally

Please follow the steps in !232772 (merged)

Grep also for audit events in log file

tail -f log/audit_json.log | grep iam_oauth
  1. Drive an accept flow: open the OAuth client's authorize URL in a browser, sign in, and click Authorize on the consent screen. Expect a JSON line in the tail with "event_name":"user_authorized_iam_oauth_application"
  2. Drive a reject flow: repeat the authorize URL, click Cancel. Expect a JSON line with "event_name":"user_rejected_iam_oauth_application".
  3. Visit http://gdk.test:3000/admin/users//audit_events and confirm the two rows appear with the expected message and the application name in the Target column.

MR acceptance checklist

Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

Edited by Daniele Bracciani

Merge request reports

Loading