gitroomhq/postiz-app · error · Error
Token request failed: ${error}
Error message
Token request failed: ${error} What it means
Generic OAuth provider base class: the provider's token endpoint returned a non-2xx while exchanging the authorization code for an access_token. The provider's response body is appended, typically containing error=invalid_client/invalid_grant/redirect_uri_mismatch.
Source
Thrown at apps/backend/src/services/auth/providers/oauth.provider.ts:71
const { tokenUrl, clientId, clientSecret, frontendUrl } = this.getConfig();
const response = await fetch(`${tokenUrl}`, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
Accept: 'application/json',
},
body: new URLSearchParams({
grant_type: 'authorization_code',
client_id: clientId,
client_secret: clientSecret,
code,
redirect_uri: `${frontendUrl}/settings`,
}),
});
if (!response.ok) {
const error = await response.text();
throw new Error(`Token request failed: ${error}`);
}
const { access_token } = await response.json();
return access_token;
}
async getUser(access_token: string): Promise<{ email: string; id: string }> {
const { userInfoUrl } = this.getConfig();
const response = await fetch(`${userInfoUrl}`, {
headers: {
Authorization: `Bearer ${access_token}`,
Accept: 'application/json',
},
});
if (!response.ok) {
const error = await response.text();
throw new Error(`User info request failed: ${error}`);View on GitHub (pinned to 0f1647f749)
Solutions
- Read the provider's error body in the message: invalid_client -> fix secret, invalid_grant -> fresh code, redirect_uri mismatch -> fix registration
- Verify FRONTEND_URL exactly matches the redirect URI registered with the provider (scheme, host, path /settings)
- Regenerate/re-verify CLIENT_ID and CLIENT_SECRET env values for that provider
- Ensure the code is exchanged exactly once, immediately after callback
Example fix
# before FRONTEND_URL=http://localhost:4200 # after — must match the provider-registered callback exactly FRONTEND_URL=https://app.example.com
Defensive patterns
Strategy: try-catch
Validate before calling
null
Type guard
null
Try / catch
try {
const token = await provider.getToken(code);
} catch (e) {
if (e instanceof Error && e.message.startsWith('Token request failed:')) {
const body = e.message.slice('Token request failed:'.length);
if (body.includes('redirect_uri')) fixRedirectUriRegistration();
else if (body.includes('invalid_grant')) restartFlow();
else throw new ConfigurationError('provider credentials', body);
}
throw e;
} Prevention
- Keep FRONTEND_URL in sync with the registered redirect URI
- Store client secrets in env and rotate on schedule
- Exchange each code exactly once, right after callback
When it happens
Trigger: Posting the code + client credentials to the provider's token URL with a wrong client_secret, an expired or already-used code, or a redirect_uri (`${frontendUrl}/settings`) that doesn't match what's registered on the provider app.
Common situations: Provider client secret rotated but env not updated; FRONTEND_URL env wrong or changed (http vs https, trailing slash) so redirect_uri mismatches; code used twice (double callback, retry logic); provider app in sandbox/test mode.
Related errors
- Token request failed: ${error}
- Organization not found
- Invalid user
- User info request failed: ${error}
- Integration not allowed
AI-assisted analysis of gitroomhq/postiz-app@0f1647f749 (2026-08-27).
Data as JSON: /api/errors/a071a10c2b17a773.
Report an issue: GitHub.