Add composite identity OAuth token authentication for GraphQL

What does this MR do and why?

Adds composite identity OAuth token authentication for GraphQL requests.

When using composite identity OAuth tokens to authenticate GraphQL requests, users were receiving "Invalid token" errors even though the same tokens worked correctly for REST API endpoints.

The issue occurs because:

  1. GraphQL uses SessionlessAuthentication#sessionless_sign_in which checks can_log_in_with_non_expired_password?
  2. For composite identity users (scoped users with composite_identity_enforced! set), this check returns false
  3. When can_log_in_with_non_expired_password? calls can?(:log_in), the Ability system performs a composite identity check that validates whether the primary service account can log in
  4. Service accounts cannot log in by design, so the check fails
  5. This prevents sessionless_sign_in from calling sign_in, leaving current_user as nil

REST API works because API::APIGuard#find_current_user! only checks can?(:access_api) and never calls sessionless_sign_in or checks can_log_in_with_non_expired_password?.

References

Screenshots or screen recordings

Before After

How to set up and validate locally

  1. Checking out master branch, enabling the feature flag duo_workflow_use_composite_identity
  2. Generate a service account oauth token
   result = ::Ai::DuoWorkflows::CreateCompositeOauthAccessTokenService.new(
     current_user: User.find(1),  # Your user
     organization: ::Organizations::Organization.first
   ).execute
   
   token = result.payload[:oauth_access_token]
   plaintext_token = token.plaintext_token
   puts "Token: #{plaintext_token}"
   puts "Expires in 1 hour at: #{token.created_at + 1.hour}"
  1. Test REST API (succeeds)
   curl -H "Authorization: Bearer <token-from-step-1>" \
        http://gdk.test:3000/api/v4/projects
  1. Test GraphQL (fails), expect {"errors":[{"message":"Invalid token"}]}
   curl -X POST \
        -H "Authorization: Bearer <token-from-step-1>" \
        -H "Content-Type: application/json" \
        -d '{"query": "query { currentUser { id username } }"}' \
        http://gdk.test:3000/api/graphql
  1. Apply the patch
  2. Test GraphQL again

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.

Related to #572965

Merge request reports

Loading