Skip to content

Locally FAIR: UI Download button and Preview fail with 404 for authorized users (session-authenticated requests get no API token injected) #12563

Description

@yesilms

Summary

When a collection is marked Locally FAIR (feature flag dataverse.feature.allow-locally-fair-data), the UI Download button and the external-tool Preview iframe both fail with HTTP 404 for users who are correctly authorized via the collection's locallyFairRoleAssignees. The same file downloads successfully via the REST API when X-Dataverse-key / ?key= is supplied. Public (non-FAIR) datasets are unaffected.

Environment

  • Dataverse v6.11 (image gdcc/dataverse:6.11-noble)
  • Feature flag: dataverse.feature.allow-locally-fair-data=1
  • Deployment: OpenShift, Payara behind an Apache reverse proxy (HTTPS termination + X-Forwarded-* headers correctly forwarded)
  • Browsers reproduced with: Edge (JSESSIONID stable across requests)

Reproduction

  1. Enable dataverse.feature.allow-locally-fair-data.
  2. Create a published collection internal; mark it Locally FAIR.
  3. Add a user (or explicit group) to PUT /api/dataverses/internal/locallyFairRoleAssignees/{roleAssignee}.
  4. Publish a dataset with an unrestricted file inside the collection.
  5. Log in as that authorized user in the browser.
  6. Click Download on the file (or Preview for a supported MIME type).

Actual behavior

Download button issues:

GET https://<host>/api/access/datafile/16?gbrecs=true
Cookie: JSESSIONID=<valid session for authorized user>
(no X-Dataverse-key header, no ?key= param)

Response:

{
  "status": "ERROR",
  "code": 404,
  "message": "API endpoint does not exist on this server. ..."
}

Preview iframe: the previewer's subsequent /api/access/datafile/16 fetch returns the same 404. External tools receive no signed URL for FAIR-hidden files.

Expected behavior

An authorized viewer (member of locallyFairRoleAssignees, either directly or through a group) should be able to download and preview files in a Locally FAIR collection from the UI, without having to manually append an API token to URLs.

Root cause analysis (confirmed by us)

  1. /api/* is stateless — it authenticates only via X-Dataverse-key header or ?key= query param. JSESSIONID is intentionally ignored. Confirmed from the logged-in browser:

    fetch('/api/users/:me', { credentials: 'include' })
    // → {"status":"ERROR","message":"User with token null not found."}
  2. Server-side authorization is correct. From inside the container, using the authorized user's token:

    curl -H "X-Dataverse-key: $TOKEN" http://localhost:8080/api/access/datafile/16
    # → HTTP 200, 720597 bytes
  3. The UI only appends ?key=<token> to /api/access/datafile/{id} links when the file itself is restricted. Locally FAIR is a collection-level visibility control; files remain "unrestricted", so the UI emits the plain URL, which then hits the FAIR check as an anonymous caller and returns 404 (the FAIR hide-as-404 semantics apply to the API too, per the docs: "API access is also blocked for unauthorized access.").

  4. Same story for external-tool previewers: no signed URL is generated for FAIR files, so the tool's fetch is anonymous → 404.

Net effect: Locally FAIR is only usable via the API when the caller supplies a token; the built-in web UI cannot preview or download FAIR content for any user, superuser included, because it does not attach any credential to those requests.

Suggested fix(es)

Any of the following would resolve the UI break.

  • (a) Treat Locally FAIR as a trigger for injecting ?key=<token> into the UI's /api/access/datafile/* and dataset-ZIP download links for the currently authenticated user (same mechanism used today for restricted files).
  • (b) Generate signed URLs ({signedUrl} placeholder) for external tools whenever the containing collection is Locally FAIR, not only for restricted files. Requires dataverse.api.signature-secret to be configured, which is already the recommended prod setting.
  • (c) Have /api/access/datafile/* (and related endpoints) fall back to accepting the JSF session (JSESSIONID) for read access when the request originates from the same-origin UI. This is a broader change and might have security implications, so (a)/(b) are preferred.

Workarounds available today

  • N/A

Related docs / code

Additional context

Happy to provide additional info and test any proposed patch on our OpenShift v6.11 deployment.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    Status
    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions