gitroomhq/postiz-app · error · Error

Invalid provider token

Error message

Invalid provider token

What it means

Apple's token endpoint responded 2xx but the JSON body contained no id_token, which is the only credential this flow uses. Without id_token the Apple sign-in cannot proceed.

Source

Thrown at apps/backend/src/services/auth/providers/apple.provider.ts:99

        'Content-Type': 'application/x-www-form-urlencoded',
      },
      body: new URLSearchParams({
        grant_type: 'authorization_code',
        code,
        redirect_uri: redirectUri || defaultRedirect(),
        client_id: clientId,
        client_secret: clientSecret(),
      }).toString(),
    });

    if (!response.ok) {
      const error = await response.text();
      throw new Error(`Token request failed: ${error}`);
    }

    const { id_token } = await response.json();
    if (!id_token) {
      throw new Error('Invalid provider token');
    }

    return id_token;
  }

  async getUser(providerToken: string) {
    const { clientId } = getConfig();
    const decoded = decode(providerToken, { complete: true });
    const { keys } = await (
      await fetch('https://appleid.apple.com/auth/keys')
    ).json();

    const key = keys.find(
      (k: { kid: string }) => k.kid === decoded?.header?.kid
    );
    if (!key) {
      throw new Error('Invalid provider token');
    }

View on GitHub (pinned to 0f1647f749)

Solutions

  1. Ensure the authorization request includes scope 'openid name email' and response_type 'code'
  2. Verify you're posting to https://appleid.apple.com/auth/token with grant_type=authorization_code
  3. Log the full token response body to see exactly which fields Apple returned
  4. If the body contains an error object, address that error (it can come with a 200 in some proxies)

Example fix

// before
const url = `?client_id=${clientId}&redirect_uri=${uri}&response_type=code`;

// after
const url = `?client_id=${clientId}&redirect_uri=${uri}` +
  `&response_type=code&scope=name%20email`; // server adds openid via response_mode form_post
Defensive patterns

Strategy: try-catch

Validate before calling

null

Type guard

const hasIdToken = (b: unknown): b is { id_token: string } =>
  typeof (b as any)?.id_token === 'string' && (b as any).id_token.length > 0;

Try / catch

try {
  const token = await appleProvider.getToken(code);
} catch (e) {
  if (e instanceof Error && e.message === 'Invalid provider token') {
    return restartFlowWithOpenIdScope();
  }
  throw e;
}

Prevention

When it happens

Trigger: Exchange succeeds at HTTP level but the response only contains an access_token (wrong response_type/scope, e.g. missing the 'openid' scope) or Apple returns an unexpected/empty body.

Common situations: The Services ID's scope configuration omits openid/name/email; requesting response_type that only yields a code+access_token; Apple behavior change in the token response shape; parsing the wrong endpoint response.

Related errors


AI-assisted analysis of gitroomhq/postiz-app@0f1647f749 (2026-08-27). Data as JSON: /api/errors/31609c19ed599128. Report an issue: GitHub.