{"record":{"id":"be949a337a202b31","repo":"toeverything/AFFiNE","slug":"authentication-callback-server-not-found-server","errorCode":null,"errorMessage":"Authentication callback server not found: ${serverBaseUrl}","messagePattern":"Authentication callback server not found: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/frontend/apps/ios/src/app.tsx","lineNumber":759,"sourceCode":"  }\n\n  const method = urlObj.searchParams.get('method');\n  const payload = JSON.parse(urlObj.searchParams.get('payload') ?? 'false');\n  const serverBaseUrl = urlObj.searchParams.get('server');\n\n  if (!method || (method !== 'magic-link' && method !== 'oauth') || !payload) {\n    throw new Error('Invalid authentication url');\n  }\n\n  let authService = frameworkProvider\n    .get(DefaultServerService)\n    .server.scope.get(AuthService);\n\n  if (serverBaseUrl) {\n    const serversService = frameworkProvider.get(ServersService);\n    const server = serversService.getServerByBaseUrl(serverBaseUrl);\n    if (!server) {\n      throw new Error(\n        `Authentication callback server not found: ${serverBaseUrl}`\n      );\n    }\n    authService = server.scope.get(AuthService);\n  }\n\n  if (method === 'oauth') {\n    await authService.signInOauth(\n      payload.code,\n      payload.state,\n      payload.provider\n    );\n  } else if (method === 'magic-link') {\n    await authService.signInMagicLink(payload.email, payload.token);\n  }\n};\n\n(window as any).nativeHandleAuthenticationCallback = async (url: string) => {","sourceCodeStart":741,"sourceCodeEnd":777,"githubUrl":"https://github.com/toeverything/AFFiNE/blob/b6de0ad51b76f3daac2d3d6325369ea623ed7ed4/packages/frontend/apps/ios/src/app.tsx#L741-L777","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Add/log in to that server inside the app once so it exists in ServersService before triggering its auth flow","Make the server param match the stored base URL exactly — same scheme, host, port, path, no trailing slash","If the default server is intended, omit the server param so DefaultServerService is used"],"exampleFix":"// before: trailing slash / wrong scheme never matches the stored URL\nconst url = `affine://authentication?method=oauth&...&server=http://example.com/`;\n// after: reuse the exact registered base URL\nconst url = `affine://authentication?method=oauth&...&server=${encodeURIComponent(server.baseUrl)}`;","handlingStrategy":"validation","validationCode":"// resolve the server before invoking the handler\nconst serverParam = new URL(url).searchParams.get('server');\nif (serverParam) {\n  const known = serversService.getServerByBaseUrl(serverParam);\n  if (!known) {\n    return promptAddServer(serverParam); // guide the user instead of throwing\n  }\n}\nawait handleAuthenticationCallback(url);","typeGuard":"const isKnownServerUrl = (url: string, servers: ServersService): boolean =>\n  servers.getServerByBaseUrl(new URL(url).searchParams.get('server') ?? '') !== undefined;","tryCatchPattern":"// catch and route to onboarding: add the server, then re-run auth\ntry {\n  await handleAuthenticationCallback(url);\n} catch (e) {\n  if (e instanceof Error && e.message.startsWith('Authentication callback server not found')) {\n    return navigateToAddServer(extractServerParam(url));\n  }\n  throw e;\n}","preventionTips":["Generate callback links from the exact server.baseUrl stored by ServersService, never reconstruct it","Normalize base URLs (strip trailing slash, lowercase scheme+host) once, at server-registration time","Omit the server param for the default server so only explicitly added servers need matching"],"tags":["ios","auth","server-url","deep-link","multi-server"],"backgroundTag":"unknown-server-url","analyzedSha":"b6de0ad51b76f3daac2d3d6325369ea623ed7ed4","analyzedAt":"2026-08-21T18:20:45.039Z","contentChangedAt":"2026-08-21T18:20:45.039Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}