Allow token authentication for design management images
What does this MR do and why?
Design management images (/-/design_management/designs/:id/(:sha/)raw_image and …/resized_image/:size) are currently only accessible to session-authenticated (browser) requests. API clients can read all design metadata — including the image URLs — through GraphQL (DesignManagement::Design.image / imageV432x230), but then have no way to actually fetch those images on non-public projects:
- the routes are not part of the REST or GraphQL API (the REST
Designentity'simage_urlpoints back at this same web route), and - web requests only accept PAT/OAuth tokens for an allowlist of request formats — RSS/ICS,
/api, repository archives, release downloads (Gitlab::Auth::AuthFinders#valid_web_access_format?) — which design images are not part of.
So a token that can read everything about a design cannot download it: clients (mobile apps, integrations, exporters) get a sign-in redirect instead of the image.
This MR adds a :design sessionless authentication format, valid only on design management image paths, and authenticates it in Projects::DesignManagement::DesignsController show actions — the same mechanism (and motivation) previously used for repository archives (#28978 (closed)) and release downloads.
Notes for reviewers:
- Authorization is unchanged.
authorize_read_design!(can?(current_user, :read_design, design)) still runs on every request; this only adds an authentication transport for a read-only endpoint. - Tokens must carry the
apiorread_apiscope (RequestAuthenticator#find_user_from_any_authentication_methodpassesscopes: [:api, :read_api], as for the other web-access formats). Insufficient scopes keep behaving as unauthenticated. - Project/group access tokens (bot users) are intentionally not added to
RequestAuthenticator#can_sign_in_bot?, matching release downloads.
How to set up and validate locally
-
On a private project, add a design to an issue (issue → Designs → upload), and create a personal access token with the
read_apiscope. -
Get the design's image URL via GraphQL:
{ project(fullPath: "<path>") { issue(iid: "<iid>") { designCollection { designs(first: 1) { nodes { image } } } } } } -
Without this change:
curl -i -H "PRIVATE-TOKEN: <token>" "<image url>"redirects to/users/sign_in. -
With this change: the same request returns the image (
200,Content-Type: image/…). A token with an insufficient scope (for exampleread_user) still gets the sign-in redirect, and a token whose user cannot read the design still gets a 404.
MR acceptance checklist
Please evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.