eyaltoledano/claude-task-master · error · AuthenticationError

AUTH_TIMEOUT

AUTH_TIMEOUT

Error message

'Authentication flow expired'

What it means

AUTH_TIMEOUT is thrown when the backend reports the flow status as 'expired' — the OAuth flow exceeded the server-side lifetime before the user finished authenticating in the browser. Unlike the client-side timeout (same code, thrown at the end of the loop), this is the server explicitly expiring the flow.

Source

Thrown at packages/tm-core/src/modules/auth/services/oauth-service.ts:397

							refreshToken: tokens.refresh_token,
							userId: tokens.user_id,
							email: tokens.email,
							expiresAt: tokens.expires_in
								? new Date(Date.now() + tokens.expires_in * 1000).toISOString()
								: undefined,
							tokenType: 'standard',
							savedAt: new Date().toISOString()
						};
					}

					case 'failed':
						throw new AuthenticationError(
							data.error_description || data.error || 'Authentication failed',
							'OAUTH_FAILED'
						);

					case 'expired':
						throw new AuthenticationError(
							'Authentication flow expired',
							'AUTH_TIMEOUT'
						);

					case 'pending':
					case 'authenticating':
						// Still waiting, continue polling
						this.logger.debug(
							`Flow status: ${data.status}, continuing to poll`
						);
						break;

					default:
						this.logger.warn(`Unknown flow status: ${data.status}`);
				}
			} catch (error) {
				if (error instanceof AuthenticationError) {
					throw error;

View on GitHub (pinned to c0c98d367c)

Solutions

  1. Call `credentials()` again immediately to start a fresh flow and complete the browser login promptly.
  2. Start the browser login as soon as the URL is produced; don't let the auth URL sit idle.
  3. If MFA/SSO prompts routinely take too long, ask the admin to extend the server-side flow TTL (client `timeout` option only affects local polling).
  4. Automate the retry: catch AUTH_TIMEOUT and re-initiate the flow once with a user prompt to finish login faster.

Example fix

// before: single attempt, expires if user is slow
const creds = await oauthService.credentials();
// after: retry once on server-side expiry
try {
  const creds = await oauthService.credentials();
} catch (e) {
  if (e instanceof AuthenticationError && e.code === 'AUTH_TIMEOUT') {
    console.error('Login expired, starting a new flow — complete it promptly.');
    return oauthService.credentials();
  }
  throw e;
}
Defensive patterns

Strategy: retry

Type guard

function isAuthTimeout(e: unknown): e is AuthenticationError {
  return e instanceof AuthenticationError && e.code === 'AUTH_TIMEOUT';
}

Try / catch

try {
  const creds = await oauthService.credentials();
} catch (e) {
  if (e instanceof AuthenticationError && e.code === 'AUTH_TIMEOUT') {
    console.error('Login flow expired — starting a new one; complete the browser step promptly.');
    return oauthService.credentials();
  }
  throw e;
}

Prevention

When it happens

Trigger: During `credentials()`, polling returns `{success:true,status:'expired'}` — the user took longer than the server's flow TTL (typically a few minutes) to complete the browser login, or never opened/completed it before expiry.

Common situations: User leaves the browser tab open but doesn't finish login; login tab closed and rediscovered after the flow expired; slow corporate SSO/multi-factor prompts exceeding the flow window; polling started long after the auth URL was generated.

Understand the failure class

Related errors


AI-assisted analysis of eyaltoledano/claude-task-master@c0c98d367c (2026-08-29). Data as JSON: /api/errors/5749880d52f71440. Report an issue: GitHub.