Summary
With --conneg enabled, an authenticated GET on a container returns a Turtle body but labels the response Content-Type: application/ld+json, regardless of the requested Accept. The same request without auth correctly returns JSON-LD. This breaks any client that trusts either the Accept negotiation or the Content-Type header (which is most of them).
Repro
Server:
JSS_SINGLE_USER_PASSWORD=hunter2 jss start --port 4443 --root ~/main --single-user --idp --conneg
Get a token:
TOKEN=$(curl -s -X POST http://localhost:4443/idp/credentials \
-H "Content-Type: application/json" \
-d '{"username":"me","password":"hunter2"}' | jq -r .access_token)
Without auth — JSON-LD body, JSON-LD content-type ✓
$ curl -sI -H "Accept: application/ld+json, text/turtle;q=0.5" http://localhost:4443/me/profile/card.jsonld | grep -i content-type
content-type: application/ld+json; charset=utf-8
$ curl -s -H "Accept: application/ld+json, text/turtle;q=0.5" http://localhost:4443/me/ | head -3
{
"@context": {
"ldp": "http://www.w3.org/ns/ldp#",
With auth — Turtle body, JSON-LD content-type ✗
$ curl -sI -H "Authorization: Bearer $TOKEN" -H "Accept: application/ld+json, text/turtle;q=0.5" http://localhost:4443/me/ | grep -i content-type
content-type: application/ld+json
$ curl -s -H "Authorization: Bearer $TOKEN" -H "Accept: application/ld+json, text/turtle;q=0.5" http://localhost:4443/me/ | head -3
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>.
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>.
@prefix xsd: <http://www.w3.org/2001/XMLSchema#>.
The body is plainly Turtle, the header says JSON-LD. Even when I request Accept: application/ld+json explicitly (no Turtle in the Accept at all), the auth path still serves Turtle.
Expected
Either:
- Body matches Accept — auth path honors the same q-weighted negotiation as the anonymous path. Default to JSON-LD (the documented native format) when client prefers it.
- Header matches body — at minimum, the Content-Type label should reflect what's actually in the body.
Probably both. JSON-LD is JSS's native format; Turtle should only come back when the client asks for it.
Why it matters
Clients that do if (contentType.includes('json')) JSON.parse(body) get a parse error on perfectly conformant requests. The mislabel is the worst part — a sniff (e.g. "first non-whitespace char is { or @") can route around it, but every consumer shouldn't have to.
Environment
- jss
0.0.155 (latest published)
- node
v24.5.0
- Linux x86_64
Likely a divergence between two response paths inside the auth middleware vs. the anonymous handler. Happy to look at the conneg layer if you want a PR.
Summary
With
--connegenabled, an authenticated GET on a container returns a Turtle body but labels the responseContent-Type: application/ld+json, regardless of the requested Accept. The same request without auth correctly returns JSON-LD. This breaks any client that trusts either the Accept negotiation or the Content-Type header (which is most of them).Repro
Server:
Get a token:
Without auth — JSON-LD body, JSON-LD content-type ✓
With auth — Turtle body, JSON-LD content-type ✗
The body is plainly Turtle, the header says JSON-LD. Even when I request
Accept: application/ld+jsonexplicitly (no Turtle in the Accept at all), the auth path still serves Turtle.Expected
Either:
Probably both. JSON-LD is JSS's native format; Turtle should only come back when the client asks for it.
Why it matters
Clients that do
if (contentType.includes('json')) JSON.parse(body)get a parse error on perfectly conformant requests. The mislabel is the worst part — a sniff (e.g. "first non-whitespace char is{or@") can route around it, but every consumer shouldn't have to.Environment
0.0.155(latest published)v24.5.0Likely a divergence between two response paths inside the auth middleware vs. the anonymous handler. Happy to look at the conneg layer if you want a PR.