URI in Profile triggers CORS Unsafe Request Header Byte rule
In the IANA registration [1], we define a media type parameter called 'profile'. Its value is a space separated list of URIs, for which we registered six initial values. These can be composed together, and new values can be added for other "constraints or conventions".
The IIIF specifications use this functionality, for example to define the specific structure of the response in an API [2] as part of the media type. Similarly in Linked Art, we do the same [3].
However, in the WHATWG specification for fetch [4], it says that the value for the Accept header is NOT CORS safe, if it has more than 128 bytes (which multiple URIs might easily cause) or (more importantly) if the value contains an unsafe header byte. The unsafe header bytes include the character ":" ... which prevents any URI or CURIE with a namespace prefix separate by : from being CORS safe.
This means that we cannot use the JSON-LD media type as registered for content negotiation via the accept header according to the fetch specification, which was much of the rationale for the profile parameter.
To resolve this, either WHATWG would need to change fetch, or W3C/IANA would need to change the definition of the media type and give some registration function for possible profile values, then all downstream specifications would need to register a safe profile value to use.
I've added the tag-needs-resolution label, as I think that's the level this would need to run up to :(
[1] https://www.w3.org/TR/json-ld11/#iana-considerations [2] https://iiif.io/api/presentation/3.0/#63-responses [3] https://linked.art/api/1.0/json-ld/#introduction [4] https://fetch.spec.whatwg.org/#ref-for-cors-unsafe-request-header-byte
You say "NOT CORS safe", but I think the issue is the header will not be "CORS-safelisted"? When that is the case, a preflight request will be used. If that succeeds, the request should be sent. This doesn't seem like a blocker for using any of these headers, just a bit more server complexity than the "simple requests" CORS case that doesn't do a preflight. You probably need to setup a Access-Control-Allow-Headers to allow Accept, others as needed, and probably want Access-Control-Max-Age to cache preflight requests if appropriate.
@pchampin had a w3id.org issue with CORS and preflights the other day, where I learned more about this topic and safelists and simple requests and redirects. https://github.com/perma-id/w3id.org/issues/4185 and https://github.com/perma-id/w3id.org/pull/4196.
I tried a simple fetch from a browser console, and it does appear to do the above behavior. No profile will skip preflight, adding profile with URL will do one, then send the request. You do need a server setup to handle CORS headers, but then it works.
await fetch(
"https://example.com/test",
{headers: {"Accept": "application/ld+json;profile=http://www.w3.org/ns/json-ld#expanded"}}
)
Of note: https://www.w3.org/TR/dx-prof-conneg/
This was discussed during the json-ld meeting on 13 November 2024.
View the transcript
Issue Discussion
bigbluehat: We're working through the project list.
gkellogg: added issues that are class 1-3.
subtopic w3c/json-ld-syntax#436
<gb> Issue 436 URI in Profile triggers CORS Unsafe Request Header Byte rule (by azaroth42) [spec:w3c] [needs discussion] [tag-needs-resolution]
gkellogg: might just create "tokens" for profile paraemters.
gkellogg: tokens not being namespaced is mitigated by the fact that the media-type is the namespace.
bigbluehat: So, it treats the media-type as the namespace.
… Profile parameters not having a colon is wide-reaching
gkellogg: not sure how we update guidance for using profile parameters.
bigbluehat: This would be a breaking change for web annotations.
… That would mean web annotations needs their own media type.
niklasl: dlehn's reply may mean this isn't as horrible as it seems.
… I think the datasets working group has done something with this.
pchampin: This doesn't seem to be a problem where things can't work, but making them work is tricky, due to pre-flight requests.
… If we expect a server to support profile-based content-negotiation, it doesn't come automatically.
… If you want to support this, you'll also need to support pre-flight requests.
<bigbluehat> q|
pchampin: This is difficult to configure and easily forgotten.
<gb> Issue 436 URI in Profile triggers CORS Unsafe Request Header Byte rule (by azaroth42) [spec:w3c] [needs discussion] [tag-needs-resolution]
bigbluehat: There were some suggestions for defining enumerated values (tokens).
<pchampin> I think it wouldn't hurt to define "short names" for the profiles in addition to the currently defined IRIs
bigbluehat: The key is to not make it a breaking change.
… This would affect the media-type registration.
niklasl: Aren't link headers defined similarly, where there are pre-defined tokens and IRIs may also be used.
bigbluehat: Browsers have made decisions which are affecting what we can do.
<bigbluehat> > When processing the "profile" media type parameter, it is important to note that its value contains one or more URIs and not IRIs. In some cases it might therefore be necessary to convert between IRIs and URIs as specified in section 3 Relationship between IRIs and URIs of [RFC3987].
https://
<niklasl> application/ld+json;profile="http://
niklasl: I think it would be good to add tokens. Rob's specific problem are more about the other uses of profiles.
… I wonder if our solution would be considered a solution for the issue; maybe parts of the issue can't be solved in the JSON-LD spec. Might recommend IIIF to use profile negotiation.
… But, using pre-flight does work, so that would be on their end.
… It's more that we put forward the design pattern and it has become more tricky.
bigbluehat: The ramifications of this are not just expand/compact/... Rob's point is for other specifications that used the same pattern.
… No we know to avoid it.
<niklasl> See also: https://
bigbluehat: There's reason to document this in the best-practices document. How this affects other specs would mean that they cannot treat profile as being extensible, and will need a new media type.
gkellogg: we might create a registry to allow other specifications to add their profile parameters without needing a new media-type.
bigbluehat: niklasl shared a document on using the profile parameter for content negotiation.
pchampin: Reaching out the that TAG would be a good idea, as other specs rely on this, and they would be impacted.
… I'd like to see their thoughts and how much we should make the effort to try to change this.
… Regarding the spec, note that this is a working draft which has been inactive for a while. This might not be the strongest argument to take before the TAG. (The dataset exchange WG)
… Part of the reason that spec is stalled is that there are contentious discussions with IETF on where it belongs.
<niklasl> From the dx-prof-conneg draft: During 2018, DXWG members had a longer discussion with the JSON-LD WG at the annual forum TPAC in Lyon, France and it was concluded that the "profile” parameter in the Accept and Content-Type headers should be seen to convey profiles that are specific to the Media Type [such as JSON-LD's expanded .... ]
pchampin: But, is there enough interest in IETF to continue the work?
niklasl: There are aspects of the draft that goes into the profile parameter of the media type is the right way to go.
… The design of IIIF and Activity Streams I appreciate more when not looking at it from an RDF perspective.
… These are more useful at the intersection of JSON and RDF, which makes it easier to create specifications in a distributed way.
… If I believed (from RDF perspective) that format is irrelevant, general content negotiation works well.
… I can see how the TAG might argue from one of these perspectives. Maybe we shouldn't invent media-types on the fly.
<pchampin> https://
pchampin: Regarding the value of using JSON-LD media-type with parameter vs a new media-type, VC has had to rely on this for a while.
… The current solution is to have a dedicated media-type with additional language to explain the relationship between the two media types.
… We might point other specs to that solution.
<niklasl> +1 to mentioning that "third" point of view (very pertinent IMHO)
bigbluehat: I think we need to move on and come back to this issue.
… It would be great to write some of these things up on the issue so that we have something coherent to bring to the TAG.
… IETF has shifted their approach, and we're stuck in the middle. In the mean time, if we can collect thoughts in the issue.
… I don't think we know enough to lay out the preferred solution.
… If we go the short-name route, we run the risk of turning into a registry.
<bigbluehat> w3c/
<gb> Issue 443 `@protected` creates unresolvable conflicts when the same term is defined in two contexts top-level (by trwnh) [spec:editorial] [wr:commenter-agreed-partial] [class-2]
Thanks for discussing it! I think we can close this particular issue -- the pre-flight does indeed solve the issue, and implementation notes in various specs in future versions could head it off completely.
That said, at a conference in Amsterdam this week there were at least 6 organizations wanting a solution for profile negotiation for non JSON-LD serializations where the profile param isn't available, and (sorry Rob, Lars and Nick) not as complicated as https://www.w3.org/TR/dx-prof-conneg/ ... just to update and try to get acceptance for Accept-Profile in the IETF: https://datatracker.ietf.org/doc/html/draft-svensson-profiled-representations-01
(The q values being one driver for this, rather than the link header on the request approach of dx-prof-conneg)
Perhaps there's sufficient convergence to at least have a call or two?
If a less complicated option can be identified then I'd be happy to revist dx-connegp to accommodate. We have one simplification idea in the wings, but am currently buried in the details of how profiles themselves need to be defined at scale, for application level informatio content choices, not lust limited serialisation options which feel more like media-type concerns.
This issue was discussed in the 2024-12-11 meeting
Topic: Profile Negotiation ✪
Hi, The meeting times are nor workable for me on a regular basis, and I thought the group had decided to go a different way than dx-connegp.
But very interesting discussion. If there is energy to revisit the dx-connegp draft and try to find a simple solution that meets needs I am happy to participate. OGC input to this work has been on hold pending othet work on best practices for OpenApi and json schema, and combination mechanisms fir JSON-LD annotations of existing schemas. We were planning to revisit all our redirect and negotiation infrastructure in March/April.
Dx-connegp already has its own concept of implementation profiles, my feel here is that it may be possible to define a very lightweight one to meet these needs with a little relaxation of the conceptual model, such as making the discovery of available profiles optional.. its by far the most complex part.
This issue was discussed in the [2025-01-29 meeting](https://json-ld.org/minutes/2025-01-29/)
Subtopic: https://github.com/w3c/json-ld-syntax/issues/436 ✪
either WHATWG would need to change fetch
FYI, we were routinely hitting this issue in practice with our RDF agents. This prompted us to propose such a change in https://github.com/whatwg/fetch/issues/878, which as you can see was not particularly well-received, and would most likely primarily apply to Linked Open Data anyway.
This was discussed during the #json-ld meeting on 12 February 2025.
View the transcript
w3c/json-ld-syntax#436
<gb> Issue 436 URI in Profile triggers CORS Unsafe Request Header Byte rule (by azaroth42) [spec:w3c] [needs discussion] [tag-needs-resolution]
pchampin: I discussed this with Yves Lafon, staff contact of the TAG.
… This restriction of fetch is considered as an important security feature, this is unlikely to go away.
… To mitigate this issue, should we (JSON-LD WG) set up a registry for short-names for profiles of application/ld+json ?
niklasl: I don't think that a registry would solve the problem.
… We need to distinguish data shapes from the semantics of data.
… Activity Streams went for a specific media-type, others may have to do that.
… This issue seems specific to an RDF mindset.
… E.g. I want RDF, and I only understand SKOS.
… I have not seen the same kind of issue in other contexts, where structure and semantics are the same.
<niklasl> ... does the web need "compound media type negotiation" ... 🤔
pchampin: actually, video formats also suffer from the coarseness of media-types
bigbluehat: CORS breaks a lot of things. I don't think Ruben's proposal will fly.
<niklasl> (Or in the video format context, I guess "Accepts-Codex", ... And in the RDF context, maybe what I really want is "Accepts-Vocabulary" ... but try to realize that through "Accepts-Profile", for better or worse...)
bigbluehat: We have been discussing recently with the people working on profile-based conneg.
pchampin: activity on the dx-connegp has been on and off for a while. We may want to provide some help.
bigbluehat: JSON-LD mostly needs to help downstream specifications know what to choose among the media type vs. profile negotiation vs. something else
… we can and should point to the profile negotiation doc when it's available
niklasl: we at the National Libarry of Sweden, would really like to see a form of profile-based conneg. I think I could spend some time on this.
… Part of it is orthogonal to JSON-LD.
bigbluehat: agreed, it is not a core issue for us.