Share via

Microsoft OAuth / Graph API returns HTTP 200 but response body is HTML instead of JSON

Anh Nguyễn Quang 0 Reputation points
2025-12-26T06:40:52.71+00:00

Title

Microsoft OAuth v2.0 token or Microsoft Graph API sometimes returns HTTP 200 with HTML response instead of JSON


Question

I am developing a web application that integrates Salesforce with Microsoft Teams, using Microsoft Graph APIs, and stores the retrieved data in AWS.

Architecture overview

Salesforce (Apex / Callout)
   ↓
Microsoft OAuth v2.0 token endpoint
   ↓
Microsoft Graph API (Teams / organization)
   ↓
AWS (data storage / processing)

Get access token

POST https://login.microsoftonline.com/common/oauth2/v2.0/token

Call Microsoft Graph

GET https://graph.microsoft.com/v1.0/organization

In some error scenarios, I am observing unexpected behavior where one of these APIs returns HTTP 200 OK, but the response body is HTML instead of JSON.


Expected behavior

OAuth token endpoint returns a JSON error response (4xx) if token issuance fails.

Microsoft Graph API returns a JSON error response (401 / 403 / 4xx) if the request is invalid or unauthorized.


Actual behavior

HTTP status code: 200 OK

Content-Type: text/html

Response body starts with:

<!DOCTYPE html>
<html>
...

JSON parsing fails with:

Unexpected character '<' while parsing JSON

Context

Because both APIs are called sequentially, it is currently unclear whether:

the OAuth token endpoint (/oauth2/v2.0/token), or

the Microsoft Graph API (/v1.0/organization)

is responsible for returning the HTML response.


Questions

Is it expected behavior for either of these endpoints to return HTTP 200 with an HTML response body in error scenarios?

Are there specific error cases where:

the token endpoint returns an HTML error page instead of JSON?

  Microsoft Graph returns an HTML page (e.g. login or error page) instead of a JSON error?
  
  1. Is there any official guidance or documentation that explains this behavior?

What is the recommended way to reliably detect and handle such responses (besides checking Content-Type) when integrating server-to-server?

Any clarification would be greatly appreciated.

Microsoft Teams | Development
Microsoft Teams | Development

Building, integrating, or customizing apps and workflows within Microsoft Teams using developer tools and APIs


4 answers

Sort by: Most helpful
  1. Kudos-Ng 15,050 Reputation points Microsoft External Staff Moderator
    2025-12-26T17:12:05.6366667+00:00

    Hi Anh Nguyễn Quang,

    Thank you for posting your question in the Microsoft Q&A forum.

    Based on my research, the behavior you observed is unexpected for server‑to‑server integrations. Under normal error conditions, these services return appropriate 4xx/5xx status codes with JSON error payloads rather than HTML. That said, there are some plausible cases that can explain what you are seeing:

    • An HTTP client or intermediary follows a redirect (or reacts to WWW-Authenticate) and lands on the interactive /authorize or login page, which correctly returns 200 + HTML but is not part of a server‑to‑server flow.
    • A reverse proxy/WAF/CDN or corporate gateway injects an HTML error page and, incorrectly, sets the status to 200, so your application receives HTML where JSON is expected.
    • Certain edge scenarios around Graph (for example, batch requests) returning an HTML response. There has been a report about an issue with this situation here: https://github.com/microsoftgraph/msgraph-sdk-dotnet/issues/2661

    To troubleshoot effectively, you can try classifying responses before parsing: only parse when Content-Type is application/json, and treat text/html (or bodies beginning with <!DOCTYPE html>/<html>) as an error, not data. Log correlation identifiers end‑to‑end by sending a client-request-id: <GUID> and capturing request-id, timestamps to make source identification and support escalation straightforward. Finally, check infrastructure so that proxies/gateways pass through graph.microsoft.com and login.microsoftonline.com without rewriting status codes or bodies, and, if you use batch, reproduce with single calls to determine whether the anomaly is batch‑specific.

    My recommended approach this situation in practice is if the response’s Content-Type is JSON, parse it; if it is HTML, treat it as an error and differentiate login HTML (from login.microsoftonline.*, indicating a misrouted interactive path or unwanted redirect) from proxy HTML (indicating infrastructure rewriting). Then apply a disciplined retry policy: for the token endpoint, retry only transient errors (5xx429temporarily_unavailableserver_error) with exponential backoff and jitter, and do not retry configuration/authentication errors (invalid_clientinvalid_grantunauthorized_clientinvalid_scope) or any HTML response; for Graph, retry 429 or any HTML (respect Retry-After) and 5xx, and do not retry 400/401/403).

    References:

    I hope the information above helpful. If you have any further questions, please feel free to share.


    If the answer is helpful, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment". 

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


  2. Deleted

    This answer has been deleted due to a violation of our Code of Conduct. The answer was manually reported or identified through automated detection before action was taken. Please refer to our Code of Conduct for more information.


    Comments have been turned off. Learn more

  3. Sayali-MSFT 5,521 Reputation points Microsoft External Staff Moderator
    2025-12-26T09:12:39.4366667+00:00

    Hello,
    Expected behavior

    OAuth token endpoint (/oauth2/v2.0/token): Returns JSON on success or JSON error bodies (4xx) on failure.

    Microsoft Graph API: Returns JSON errors for auth/permission or request issues (4xx/401/403).

    1. Why HTML responses sometimes appear
      • Calling an interactive endpoint (e.g., /authorize) instead of /token.
      • Internal service errors (AAD/Graph outage, login error pages).
      • Redirects caused by misconfiguration that are automatically followed.
      • In rare cases, Graph may surface HTML error pages (e.g., “Service Unavailable”), sometimes even with a 200 status.
    2. SDK behavior
      • SDKs often detect text/html and throw parsing errors like “Content type text/html does not have a factory registered…”.
    3. Best practices for detection & handling
      1. Validate status and headers: Only parse JSON when status is 2xx and Content-Type is application/json.
      2. Graceful parsing: Wrap JSON parsing in try/catch and log raw responses on failure.
      3. Detect HTML: If the body starts with <, treat it as HTML; log headers like X-Ms-Ags-Diagnostic.
      4. Differentiate causes:
        • Token endpoint: ensure correct endpoint, application/x-www-form-urlencoded, no redirects.
        • Graph: verify Authorization header, permissions, and endpoint.
      5. Retries: For transient, service-level HTML errors, use exponential backoff and retry.
      Reference Document-1.https://learn.microsoft.com/en-us/graph/errors
    0 comments No comments

  4. Q&A Assist
    2025-12-26T06:41:05.2366667+00:00
    AI generated content. This question contains an answer created with AI from Q&A Assist. Learn more

    It is not expected behavior for the Microsoft OAuth v2.0 token endpoint or the Microsoft Graph API to return an HTTP 200 status code with an HTML response body in error scenarios. Typically, these endpoints should return a JSON error response with appropriate HTTP status codes (like 4xx) when an error occurs.

    However, there are specific cases where you might encounter such behavior:

    1. OAuth Token Endpoint: If there is a misconfiguration or an unexpected issue (like a server error), it might return an HTML error page instead of a JSON response. This is not standard behavior and indicates a problem that needs to be addressed.
    2. Microsoft Graph API: Similar to the token endpoint, if there is an issue with the request or a server-side error, the API may return an HTML page (like a login or error page) instead of the expected JSON error response. This can happen if the request is malformed or if there is a redirect to an error page.

    Official Guidance

    While the documentation does not explicitly cover every edge case, it is advisable to check the official Microsoft Graph documentation for error handling and response formats. This can provide insights into expected behaviors and error codes.

    To reliably detect and handle such responses:

    • Check the Content-Type header: If it is text/html, you can assume that the response is not in the expected JSON format.
    • Implement error handling logic: Always handle unexpected status codes and content types gracefully in your application. This can include logging the response for further investigation.
    • Use a try-catch block: When parsing the JSON response, use a try-catch block to handle any parsing errors that may occur due to unexpected content.

    In summary, while receiving an HTML response with a 200 status code is not expected, it can occur due to misconfigurations or errors. Implementing robust error handling and logging will help you manage such scenarios effectively.


    References:

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.