Skip to content

GitLab GraphQL requests do not refresh expired PKCE tokens #7931

Description

@JackSpiece

Describe the bug

The PKCE refresh path added in #7854 only runs through API.requestFunction. With use_graphql: true, Apollo HTTP Link calls fetch directly. If the first API call after the OAuth access token expires is a GraphQL query, it fails with a 401 and the stored refresh token is never used.

GitLab documents invalid GraphQL authentication as an HTTP 401 with {"errors":[{"message":"Invalid token"}]}, while the current REST refresh path recognizes the OAuth {"error":"invalid_token"} shape.

I reproduced this on current main with a focused test. It returns a GraphQL 401 for Bearer EXPIRED_TOKEN, expects the request to refresh and retry with Bearer NEW_TOKEN, and currently fails on the first response with Network error: Response not successful: Received status code 401.

To Reproduce

  1. Configure the GitLab backend with PKCE and use_graphql: true.
  2. Sign in and let the two-hour OAuth access token expire.
  3. Make a collection request that uses the GraphQL path before any REST request refreshes the token.
  4. The request fails with a 401 instead of refreshing.

Expected behavior

GraphQL should use the same behavior as REST: refresh the PKCE token pair, persist the rotated credentials, and retry the failed request once. Concurrent failures should continue sharing the existing refresh promise.

Screenshots

Not applicable.

Applicable Versions:

CMS configuration

backend:
  name: gitlab
  auth_type: pkce
  app_id: your-app-id
  use_graphql: true

Additional context

GitLab GraphQL authentication docs: https://docs.gitlab.com/api/graphql/#authentication

The smallest fix I see is to route Apollo HTTP Link through the backend request function and recognize GitLab GraphQL invalid-token responses there. That would keep refresh coalescing and credential persistence in one place. I can send the regression test and patch if this direction looks right.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions