toeverything/AFFiNE · error

Invalid authentication url

Error message

Invalid authentication url

What it means

The iOS app's deep-link handler only processes URLs whose hostname is 'authentication'; it then requires a method query param of exactly 'magic-link' or 'oauth' and a truthy JSON-parsed payload param. Missing method, an unknown method, or a payload that parses to a falsy value throws 'Invalid authentication url' (app.tsx:724). A malformed payload param throws a SyntaxError from JSON.parse even earlier, at line 720.

Source

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

  notify.error({
    title: I18n['com.affine.auth.toast.title.failed'](),
    message: getErrorMessage(error, fallback),
  });
};

const handleAuthenticationCallback = async (url: string) => {
  const urlObj = new URL(url);

  if (urlObj.hostname !== 'authentication') {
    return;
  }

  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') {

View on GitHub (pinned to b6de0ad51b)

Solutions

  1. Capture the exact incoming URL and inspect its query params (method, payload, server) before anything else
  2. Emit links in the canonical form: <scheme>://authentication?method=oauth|magic-link&payload=<encodeURIComponent(JSON)>&server=<baseUrl>
  3. Make sure payload parses to a truthy JSON object ({code,state,provider} for oauth; {email,token} for magic-link)
  4. Regenerate the callback with the current auth flow (updated app version) rather than a saved link

Example fix

// before: unencoded payload breaks the query string
const url = `affine://authentication?method=oauth&payload=${JSON.stringify(p)}`;
// after: encode every parameter value
const url = `affine://authentication?method=oauth&payload=${encodeURIComponent(JSON.stringify(p))}`;
Defensive patterns

Strategy: validation

Validate before calling

// validate the callback URL before acting on it
const u = new URL(url);
if (u.hostname !== 'authentication') return;
const method = u.searchParams.get('method');
let payload: unknown;
try {
  payload = JSON.parse(u.searchParams.get('payload') ?? 'null');
} catch {
  return notifyInvalidLink();
}
if (method !== 'magic-link' && method !== 'oauth') return notifyInvalidLink();
if (!payload || typeof payload !== 'object') return notifyInvalidLink();
await handleAuthenticationCallback(url);

Type guard

const isAuthCallbackUrl = (url: string): boolean => {
  try {
    const u = new URL(url);
    if (u.hostname !== 'authentication') return false;
    const method = u.searchParams.get('method');
    if (method !== 'magic-link' && method !== 'oauth') return false;
    const p = u.searchParams.get('payload');
    if (!p) return false;
    const payload = JSON.parse(p);
    return !!payload && typeof payload === 'object';
  } catch {
    return false;
  }
};

Try / catch

// already the app's pattern: notify, never crash the listener
handleAuthenticationCallback(url).catch(error =>
  notifyAuthenticationError(error, 'Failed to handle authentication callback')
);

Prevention

When it happens

Trigger: A callback URL like affine://authentication?foo=1 (no method), ...?method=saml (unsupported), ...?payload=false / payload=null, or payload absent. Also any payload that is valid JSON but evaluates falsy.

Common situations: Hand-built or truncated deep links during testing; URL-encoding bugs where the payload param is dropped or cut at an unencoded character (e.g. '{' or '&'); stale links generated by an older app/auth-flow version; custom-scheme routing mangling query strings.

Understand the failure class

Related errors


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