Fetch request to web API returns HTML instead of JSON

Hello everyone,

I’ve been trying to connect a script to the web API with a custom token, as shown below. However, each time, it returns an HTML file instead of a JSON response. The HTML seems to be the login page. I saw here that this sometimes happens when you’re not logged in. I’m sure I’m doing the request wrong, so could you help me figure it out?

const TOKEN = "my-token"

fetch("https://qa.dhis2-minsal.org/api/users", {
    headers: {
        "Authorization": "ApiToken " + TOKEN,
        "Accept": "application/json"
    }
})
.then(resp => {
    console.log(resp);
    return resp.json();
})
.then(data => {
    console.log(data);
});

I get this response:

undefined:1
<!DOCTYPE HTML>
^

SyntaxError: Unexpected token '<', "<!DOCTYPE "... is not valid JSON
    at JSON.parse (<anonymous>)
    at parseJSONFromBytes (node:internal/deps/undici/undici:5731:19)
    at successSteps (node:internal/deps/undici/undici:5712:27)
    at fullyReadBody (node:internal/deps/undici/undici:4609:9)
    at process.processTicksAndRejections (node:internal/process/task_queues:105:5)
    at async consumeBody (node:internal/deps/undici/undici:5721:7)

Node.js v22.13.0

Thanks in advance!

1 Like

Sorry for the troubles here @nasha. I don’t see anything incorrect with your request and tried it out with our demo instance Login app | DHIS2 (after generating a token in user profile app)

Have you checked that the PAT that you have generated has the appropriate authority to access the users app?

1 Like

Thank you for your response! I tried the code on the demo instance, and it worked for me as well. I then tested it again on three of my instances (production, QA, and a local instance), but now I am encountering a 401 Unauthorized error. I believe the issue lies elsewhere. I made sure to change the URL and token.

I reviewed the token authorities and noticed that the demo instance has more authorities than any of my instances. However, regardless of what I request, I consistently receive the same error.

Since you mentioned it, these are the user-related authorities I have:

  • F_REPLICATE_USER
  • F_USER_ADD
  • F_USER_ADD_WITHIN_MANAGED_GROUP
  • F_USER_DELETE_WITHIN_MANAGED_GROUP
  • F_USER_GROUPS_READ_ONLY_ADD_MEMBERS
  • F_USER_VIEW
  • F_USERGROUP_MANAGING_RELATIONSHIPS_ADD
  • F_USERGROUP_MANAGING_RELATIONSHIPS_VIEW
  • F_USERGROUP_PUBLIC_ADD
  • F_USERROLE_PUBLIC_ADD
  • M_dhis-web-user

Hi @nasha

+1 to this issue

My team and I have run into this exact problem too — getting a 200 with HTML instead of a proper 403 + JSON makes API workflows much harder to debug.

Pain points:

  • Forces clients to parse HTML to detect auth failures
  • Breaks standard error handling (e.g., resp.json() crashes)
  • Masks real issues (is it auth? CORS? server error?)

Suggested fix:

{
  "status": 403,
  "message": "Authentication required"
}

Hope the core team can prioritize this! :rocket:

1 Like

Thanks for the follow-up post!

@bsiele and @nasha would anyone of you be interested in creating a Jira ticket with these details? I think you can choose ‘bug’ issue for now: Jira.DHIS2.org

Please share the link to the ticket here so I can follow-up with the team as well as other community members can watch the ticket for updates.

Thanks!