mastra-ai/mastra · error
Failed to fetch user info from Auth0
Error message
Failed to fetch user info from Auth0
What it means
MastraAuthAuth0 verifies a user's access token by calling Auth0's standard /userinfo endpoint (https://<domain>/userinfo) with a 10-second timeout. If the HTTP response status is not OK (e.g. 401 invalid/expired token, 403, 429, 5xx), the provider throws this generic error. It means Auth0 rejected or could not serve the userinfo request for the supplied bearer token.
Solutions
- Verify the access token is a valid, unexpired Auth0 token for the correct audience — re-authenticate the user to obtain a fresh token.
- Check the Auth0 domain configuration (options.domain / AUTH0_DOMAIN) matches your tenant, e.g. 'your-tenant.us.auth0.com', with no stray https:// or trailing slash.
- Log userInfoResponse.status in a local repro to distinguish 401 (bad token) from 403/429/5xx (permissions, rate limit, outage).
- Confirm network egress: the provider hits https://<domain>/userinfo with a 10s timeout; ensure proxies/firewalls allow it.
Example fix
// before: token minted for wrong audience, 401 on /userinfo
const auth = new MastraAuthAuth0({ domain: 'wrong-tenant.auth0.com' });
// after: correct tenant domain and fresh audience-correct token
const auth = new MastraAuthAuth0({ domain: 'my-tenant.us.auth0.com' });
// client obtains token with audience matching the API registered in Auth0 Defensive patterns
Strategy: try-catch
Validate before calling
if (!accessToken || !domain) throw new Error('Auth0 access token and domain are required before verifying user info'); Type guard
function isAuth0AuthError(e: unknown): e is Error & { message: 'Failed to fetch user info from Auth0' } {
return e instanceof Error && e.message === 'Failed to fetch user info from Auth0';
} Try / catch
try {
await authConfig.verifyToken(token);
} catch (e) {
if (isAuth0AuthError(e)) {
// treat as 401: force client re-authentication
return respondUnauthorized('Auth0 rejected the token; re-authenticate');
}
throw e;
} Prevention
- Keep AUTH0_DOMAIN and client configuration in validated env checks at boot.
- Refresh access tokens before expiry on the client instead of forwarding stale tokens.
- Monitor Auth0 tenant status/rate limits; back off on 429 before retrying.
When it happens
Trigger: Any call path that resolves user info (e.g. authenticateUser/verifyToken) where fetch(`https://${this.domain}/userinfo`, { headers: { Authorization: Bearer <accessToken> } }) returns userInfoResponse.ok === false — expired/revoked/malformed access token, wrong Auth0 domain, audience mismatch, network/gateway errors, or the 10s AbortSignal.timeout firing (which surfaces as a fetch rejection/timeout before this throw, but non-2xx triggers the throw).
Common situations: Misconfigured AUTH0_DOMAIN env var (typo or wrong tenant), access tokens issued for a different API audience than the domain expects, expired or revoked tokens forwarded from the client, Auth0 tenant outages or rate limiting (429), and self-signed/corporate proxy TLS failures.
Related errors
- Token exchange failed
- Failed to fetch user info from Clerk
- Failed to initiate OpenAI Codex device authorization
- Failed to start OAuth callback server: ports
- GitHub OAuth token exchange failed
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/eaf3ceebbd4d19a2.
Report an issue: GitHub.
Appendix: source
Thrown at auth/auth0/src/index.ts:636
const params = new URLSearchParams({
client_id: self.clientId!,
returnTo: redirectUri,
});
return `https://${self.domain}/v2/logout?${params.toString()}`;
};
}
/**
* Fetch user info from Auth0's /userinfo endpoint.
*/
private async _fetchUserInfo(accessToken: string): Promise<EEUser> {
const userInfoResponse = await fetch(`https://${this.domain}/userinfo`, {
headers: { Authorization: `Bearer ${accessToken}` },
signal: AbortSignal.timeout(10_000), // 10 second timeout
});
if (!userInfoResponse.ok) {
throw new Error('Failed to fetch user info from Auth0');
}
const userInfo = (await userInfoResponse.json()) as {
sub: string;
email?: string;
name?: string;
picture?: string;
};
return {
id: userInfo.sub,
email: userInfo.email,
name: userInfo.name,
avatarUrl: userInfo.picture,
};
}
// ============================================================================View on GitHub (pinned to 75dd419e61)