toeverything/AFFiNE · error

Authentication callback server not found: ${serverBaseUrl}

Error message

Authentication callback server not found: ${serverBaseUrl}

What it means

When an authentication callback URL carries a server param, the iOS app resolves the AuthService from ServersService.getServerByBaseUrl(serverBaseUrl). No registered server matches that base URL, so no scope can be resolved and the handler throws (app.tsx:35). Without a server param the default server would be used instead.

Source

Thrown at packages/frontend/apps/ios/src/app.tsx:759

  }

  const method = urlObj.searchParams.get('method');
  const payload = JSON.parse(urlObj.searchParams.get('payload') ?? 'false');
  const serverBaseUrl = urlObj.searchParams.get('server');

  if (!method || (method !== 'magic-link' && method !== 'oauth') || !payload) {
    throw new Error('Invalid authentication url');
  }

  let authService = frameworkProvider
    .get(DefaultServerService)
    .server.scope.get(AuthService);

  if (serverBaseUrl) {
    const serversService = frameworkProvider.get(ServersService);
    const server = serversService.getServerByBaseUrl(serverBaseUrl);
    if (!server) {
      throw new Error(
        `Authentication callback server not found: ${serverBaseUrl}`
      );
    }
    authService = server.scope.get(AuthService);
  }

  if (method === 'oauth') {
    await authService.signInOauth(
      payload.code,
      payload.state,
      payload.provider
    );
  } else if (method === 'magic-link') {
    await authService.signInMagicLink(payload.email, payload.token);
  }
};

(window as any).nativeHandleAuthenticationCallback = async (url: string) => {

View on GitHub (pinned to b6de0ad51b)

Solutions

  1. Add/log in to that server inside the app once so it exists in ServersService before triggering its auth flow
  2. Make the server param match the stored base URL exactly — same scheme, host, port, path, no trailing slash
  3. If the default server is intended, omit the server param so DefaultServerService is used

Example fix

// before: trailing slash / wrong scheme never matches the stored URL
const url = `affine://authentication?method=oauth&...&server=http://example.com/`;
// after: reuse the exact registered base URL
const url = `affine://authentication?method=oauth&...&server=${encodeURIComponent(server.baseUrl)}`;
Defensive patterns

Strategy: validation

Validate before calling

// resolve the server before invoking the handler
const serverParam = new URL(url).searchParams.get('server');
if (serverParam) {
  const known = serversService.getServerByBaseUrl(serverParam);
  if (!known) {
    return promptAddServer(serverParam); // guide the user instead of throwing
  }
}
await handleAuthenticationCallback(url);

Type guard

const isKnownServerUrl = (url: string, servers: ServersService): boolean =>
  servers.getServerByBaseUrl(new URL(url).searchParams.get('server') ?? '') !== undefined;

Try / catch

// catch and route to onboarding: add the server, then re-run auth
try {
  await handleAuthenticationCallback(url);
} catch (e) {
  if (e instanceof Error && e.message.startsWith('Authentication callback server not found')) {
    return navigateToAddServer(extractServerParam(url));
  }
  throw e;
}

Prevention

When it happens

Trigger: A deep link whose server param is not byte-identical to any server registered in the app: trailing slash, http vs https, different port, different casing, or a server that was never added/signed-in within the app.

Common situations: Authenticating against a self-hosted instance that was not added to the app first; link-generation code normalizing URLs differently than the app's storage; app data reset or account/server list cleared while an old callback link is reopened.

Understand the failure class

Related errors


AI-assisted analysis of toeverything/AFFiNE@b6de0ad51b (2026-08-21). Data as JSON: /api/errors/be949a337a202b31. Report an issue: GitHub.