restsharp/RestSharp · error · InvalidOperationException
Token endpoint returned an invalid response: {body}
Error message
Token endpoint returned an invalid response: {body} What it means
Thrown by the OAuth2 endpoint authenticator when the token endpoint returned HTTP success (2xx) but the deserialized response body either is null or has an empty AccessToken. This means the body did not conform to the expected JSON token shape even though the status code was OK.
Source
Thrown at src/RestSharp/Authenticators/OAuth2/OAuth2EndpointAuthenticatorBase.cs:96
var parameters = BuildRequestParameters();
if (TokenRequest.ExtraParameters != null) {
foreach (var kvp in TokenRequest.ExtraParameters)
parameters[kvp.Key] = kvp.Value;
}
using var content = new FormUrlEncodedContent(parameters);
using var response = await _tokenClient.PostAsync(TokenRequest.TokenEndpointUrl, content, cancellationToken).ConfigureAwait(false);
var body = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
if (!response.IsSuccessStatusCode)
throw new HttpRequestException($"Token request failed with status {response.StatusCode}: {body}");
var tokenResponse = JsonSerializer.Deserialize<OAuth2TokenResponse>(body);
if (tokenResponse == null || string.IsNullOrEmpty(tokenResponse.AccessToken))
throw new InvalidOperationException($"Token endpoint returned an invalid response: {body}");
_accessToken = tokenResponse.AccessToken;
_tokenExpiry = tokenResponse.ExpiresIn.HasValue
? DateTimeOffset.UtcNow.AddSeconds(tokenResponse.ExpiresIn.Value) - TokenRequest.ExpiryBuffer
: DateTimeOffset.MaxValue;
OnTokenResponse(tokenResponse);
TokenRequest.OnTokenRefreshed?.Invoke(tokenResponse);
return _accessToken;
}
finally {
_lock.Release();
}
}
public void Dispose() {
if (_disposeClient) _tokenClient.Dispose();View on GitHub (pinned to 6a50821692)
Solutions
- Capture the body included in the exception message and inspect its structure against OAuth2TokenResponse.
- Confirm TokenEndpointUrl points to the real token API route, not a browser-facing login page.
- If the provider uses different JSON casing, customize the JSON serialization or map fields accordingly.
- Verify the IdP returns the token in the standard 'access_token' field.
Example fix
// before
// token endpoint returns { "accessToken": "..." } (camelCase)
// after
// ensure the endpoint returns { "access_token": "..." } (snake_case)
// or configure a custom JSON deserializer matching the provider's contract Defensive patterns
Strategy: try-catch
Try / catch
try { await authenticator.Authenticate(client, request, ct); } catch (InvalidOperationException ex) when (ex.Message.Contains("invalid response")) { /* capture body, verify endpoint shape/casing */ } Prevention
- Confirm the token endpoint URL points to the API token route, not an HTML login page.
- Verify the IdP returns 'access_token' in the response JSON.
- Inspect the body in the exception message to detect shape/casing mismatches.
When it happens
Trigger: Token endpoint returns 200 with a body that is not valid JSON for OAuth2TokenResponse, or JSON that lacks the access_token field, e.g. an HTML login page, an error envelope, or a different field naming (access_token nested under 'data').
Common situations: Token endpoint URL actually points to an HTML login/consent page rather than the API token route; the IdP uses a non-standard response shape (e.g. camelCase vs snake_case mismatch); a proxy/CDN injected an HTML error page with a 200 status; mismatch between System.Text.Json default casing and the provider's casing.
Related errors
- Token request failed with status {response.StatusCode}: {bod
- Using query parameters in the base URL is not supported for
- Only HMAC-SHA1, HMAC-SHA256, and RSA-SHA1 are currently supp
- Response content is null
AI-assisted analysis of restsharp/RestSharp@6a50821692 (2026-08-13).
Data as JSON: /api/errors/21a9268999961193.
Report an issue: GitHub.