ToolJet/ToolJet · error · QueryError
access_token not found in the response
Error message
access_token not found in the response
What it means
Thrown after a successful (2xx) refresh-token response when the parsed body has no access_token field. The data payload includes the responseObject and responseHeaders so the caller can see exactly what the IdP returned. It indicates the IdP accepted the request but returned a body shape this code does not recognize as a valid token response.
Source
Thrown at marketplace/plugins/common/lib/oauth.ts:344
if (!(response.statusCode >= 200 || response.statusCode < 300)) {
throw new QueryError(
'could not connect to Oauth server. status code',
JSON.stringify({ statusCode: response.statusCode }),
{
responseObject: {
statusCode: response.statusCode,
responseBody: response.body,
},
responseHeaders: response.headers,
}
);
}
if (result['access_token']) {
accessTokenDetails['access_token'] = result['access_token'];
accessTokenDetails['refresh_token'] = result['refresh_token'] || refreshToken;
} else {
throw new QueryError(
'access_token not found in the response',
{},
{
responseObject: {
statusCode: response.statusCode,
responseBody: response.body,
},
responseHeaders: response.headers,
}
);
}
return accessTokenDetails;
};
View on GitHub (pinned to 20602a8e10)
Solutions
- Inspect error.data.responseObject.responseBody to see the actual IdP response body and compare it to the expected OAuth2 token shape.
- If the token is nested (e.g., under data or result), the IdP is non-compliant; you need adapter code or the correct endpoint.
- On the IdP admin side, enable the refresh_token grant and the offline_access equivalent scope for this app.
- Confirm access_token_url points to the token endpoint, not the authorize or userinfo endpoint.
- Re-authorize if the IdP requires periodic re-consent and returned a 200 'consent_required' envelope.
Defensive patterns
Strategy: type-guard
Validate before calling
function hasAccessToken(body: any): boolean {
return body != null && typeof body.access_token === 'string' && body.access_token.length > 0;
}
// after the refresh response, before trusting it:
if (!hasAccessToken(result)) { /* surface IdP response body for diagnosis */ } Type guard
function isTokenResponse(o: any): o is { access_token: string; refresh_token?: string } {
return o != null && typeof o.access_token === 'string' && o.access_token.length > 0;
} Try / catch
try { await getRefreshedToken(...); }
catch (e) {
if (e instanceof QueryError && e.message === 'access_token not found in the response') {
// e.data.responseObject.responseBody shows what the IdP actually returned; likely needs IdP config fix
}
throw e;
} Prevention
- Verify the IdP app registration has the refresh_token grant enabled.
- Confirm access_token_url is the token endpoint, not authorize/userinfo.
- Log the response body when access_token is absent so non-standard envelopes are diagnosable.
When it happens
Trigger: result = JSON.parse(response.body) succeeds but result['access_token'] is falsy. Causes: the IdP returned an error envelope with 200 status; the refresh_token grant is not enabled on the app registration; the response nests the token under a different key (e.g., data.access_token); the response is a non-token JSON object (rate-limit notice, consent required).
Common situations: Custom/private IdPs with non-standard token envelopes; app registration missing the refresh_token grant type; the consent screen was skipped and the IdP returned a 200 with an error body; the wrong access_token_url was used (hit a different endpoint that returns JSON without access_token).
Related errors
- Refresh token not found
- Missing required fields in sourceOptions
- could not connect to Oauth server. status code
- Query could not be completed
- MISSING_OAUTH_CREDENTIALS
AI-assisted analysis of ToolJet/ToolJet@20602a8e10 (2026-08-13).
Data as JSON: /api/errors/95d173ad2ded694a.
Report an issue: GitHub.