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_applicationuser_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 usestarget: 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 resultingtarget_type: "User"/target_details: "<app name>"mismatch is visible in GraphQL and CSV export but acceptable: no code resolvestarget_type: "User"back to a record for audit events, no admin filtering bytarget_typeexists, and the UI only displaystarget_details.additional_details:application_id— the IAM-issued OAuth client idapplication_name— same astarget_details, kept for structured accessscopes— the OAuth application's registered scopes (fromclient.scopesin the IAM consent challenge response)requested_scopes— scopes requested for this consentgranted_scopes— scopes actually granted (equalsrequested_scopeson accept,[]on reject)user_agent— captured fromrequest.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.
scopeandtarget:@user. Multi-cell-safe. No dependency on the OAuth application existing in the local Rails database. Discussed in MR comment.target_detailsis theclient_name. Mild duplication withadditional_details.application_nameis 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 existinguser_authorized_oauth_application.ymlandoauth_application_created.yml.
References
- Issue: #589572
- Depends on: !232772 (merged) (consent flow controller, view, and routes). Will be rebased and merged after that MR.
- Login-flow: !225853 (merged)
Screenshots
How to set up and validate locally
With normal consent flow
Please follow the steps in !232772 (merged)
Grep also for audit events in log file
tail -f log/audit_json.log | grep iam_oauth- 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"
- Drive a reject flow: repeat the authorize URL, click Cancel. Expect a JSON line with "event_name":"user_rejected_iam_oauth_application".
- 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.
