toeverything/AFFiNE · error · InvalidAuthState
invalid_auth_state
invalid_auth_state
Error message
Invalid auth state. You might start the auth progress from another device.
What it means
OpenAppService.verifySignInCode consumes a one-time challenge of type 'open_app_sign_in' (created with a 5-minute TTL) and throws InvalidAuthState (invalid_auth_state) when consumption returns no payload or the payload lacks a userId - i.e. the code from the web 'open in app' flow is unknown, expired, or already used.
Solutions
- Generate a fresh code in the web app and resubmit immediately (within 5 minutes)
- Never retry the same code after a failure - always start a new challenge
- Copy the full code without truncation
- Check the device clock if freshly generated codes still fail
Defensive patterns
Strategy: try-catch
Validate before calling
const OPEN_APP_CODE_TTL_MS = 5 * 60 * 1000;
function isCodeStillValid(issuedAt: number): boolean {
return Date.now() - issuedAt < OPEN_APP_CODE_TTL_MS;
} Try / catch
try {
await verifySignInCode(code);
} catch (e) {
if (isAffineErrorCode(e, 'invalid_auth_state')) {
const fresh = await generateNewOpenAppCode(); // codes are single-use, 5-minute TTL
await verifySignInCode(fresh);
} else throw e;
} Prevention
- Submit open-app codes immediately after generation; never reuse them
- On any failure, restart the challenge instead of retrying the same code
When it happens
Trigger: Entering/scanning an open-app code more than 5 minutes after it was generated; re-submitting a code that already succeeded (challenges are single-use); a mistyped or truncated code; the challenge record expiring server-side before submission.
Common situations: Users letting the QR/code screen sit before scanning; retries after network failures double-submitting the same code; copy/paste losing characters; clock skew between issuing and consuming services.
Related errors
AI-assisted analysis of toeverything/AFFiNE@b4c8548c09 (2026-08-18).
Data as JSON: /api/errors/d9fe744f3cfc7808.
Report an issue: GitHub.
Appendix: source
Thrown at packages/backend/server/src/core/auth/open-app.ts:27
export class OpenAppAuthService {
constructor(private readonly challenges: AuthChallengeStore) {}
async createSignInCode(user: CurrentUser) {
return this.challenges.create(
'open_app_sign_in',
{ userId: user.id },
5 * 60 * 1000
);
}
async verifySignInCode(code: string): Promise<VerifiedIdentity> {
const payload = await this.challenges.consume<{ userId?: string }>(
'open_app_sign_in',
code
);
if (!payload?.userId) {
throw new InvalidAuthState();
}
return { userId: payload.userId, method: 'open_app' };
}
}
View on GitHub (pinned to b4c8548c09)