danny-avila/LibreChat · error · Error

idToken is missing

Error message

idToken is missing

What it means

Thrown by the Apple Sign-In strategy's profile extractor when the idToken passed into the passport-apple verify callback is falsy. The idToken is the JWT Apple issues that carries the user's `sub`, `email`, and `name` claims; without it there is no identity to decode (the next line runs `jwt.decode(idToken)`), so the strategy aborts before any user lookup. It is a hard guard — the error propagates out of `getProfileDetails` through `socialLogin`'s try/catch straight to passport as `cb(error)`, i.e. an internal error rather than a clean authentication failure.

Source

Thrown at api/strategies/appleStrategy.js:16

const jwt = require('jsonwebtoken');
const { logger } = require('@librechat/data-schemas');
const { Strategy: AppleStrategy } = require('passport-apple');
const socialLogin = require('./socialLogin');

/**
 * Extract profile details from the decoded idToken
 * @param {Object} params - Parameters from the verify callback
 * @param {string} params.idToken - The ID token received from Apple
 * @param {Object} params.profile - The profile object (may contain partial info)
 * @returns {Object} - The extracted user profile details
 */
const getProfileDetails = ({ idToken, profile }) => {
  if (!idToken) {
    logger.error('idToken is missing');
    throw new Error('idToken is missing');
  }

  const decoded = jwt.decode(idToken);

  logger.debug(`Decoded Apple JWT: ${JSON.stringify(decoded, null, 2)}`);

  return {
    email: decoded.email,
    id: decoded.sub,
    avatarUrl: null, // Apple does not provide an avatar URL
    username: decoded.email ? decoded.email.split('@')[0].toLowerCase() : `user_${decoded.sub}`,
    name: decoded.name
      ? `${decoded.name.firstName} ${decoded.name.lastName}`
      : profile.displayName || null,
    emailVerified: true, // Apple verifies the email
  };
};

View on GitHub (pinned to 5ff282f900)

Solutions

  1. Verify the Apple Sign-In configuration in the Apple Developer console: the Service ID's Return URLs must include `${DOMAIN_SERVER}${APPLE_CALLBACK_URL}` exactly.
  2. Confirm `APPLE_CLIENT_ID`, `APPLE_TEAM_ID`, `APPLE_KEY_ID`, and `APPLE_PRIVATE_KEY_PATH` are all set and the private key file is readable by the process.
  3. Log the full verify-callback arguments at the top of `socialLogin`'s wrapper (or temporarily in `getProfileDetails`) to confirm which positional argument is actually undefined.
  4. Ensure no reverse proxy or middleware consumes/rewrites the Apple callback POST body before passport-apple parses it.

Example fix

// before
const getProfileDetails = ({ idToken, profile }) => {
  if (!idToken) {
    logger.error('idToken is missing');
    throw new Error('idToken is missing');
  }
  const decoded = jwt.decode(idToken);
// after — fail as a passport auth-failure with a stable code instead of a 500
const getProfileDetails = ({ idToken, profile }) => {
  if (!idToken) {
    logger.error('idToken is missing from Apple callback');
    const err = new Error('Apple did not return an id_token');
    err.code = 'APPLE_ID_TOKEN_MISSING';
    throw err;
  }
  const decoded = jwt.decode(idToken);
Defensive patterns

Strategy: validation

Validate before calling

// Before invoking the Apple strategy, assert the env is complete
function assertAppleConfig() {
  const required = ['APPLE_CLIENT_ID', 'APPLE_TEAM_ID', 'APPLE_KEY_ID', 'APPLE_PRIVATE_KEY_PATH', 'APPLE_CALLBACK_URL'];
  const missing = required.filter((k) => !process.env[k]);
  if (missing.length) throw new Error(`Apple Sign-In misconfigured: missing ${missing.join(', ')}`);
}
assertAppleConfig();

Type guard

function hasIdToken(args: unknown): args is { idToken: string } {
  return typeof args === 'object' && args !== null &&
    typeof (args as any).idToken === 'string' && (args as any).idToken.length > 0;
}

Try / catch

// In socialLogin's wrapper — distinguish missing-token from other failures
try {
  const details = getProfileDetails({ idToken, profile });
} catch (err) {
  if (err.message === 'idToken is missing') {
    return cb(null, false, { message: 'Apple did not return an identity token' });
  }
  return cb(err);
}

Prevention

When it happens

Trigger: The passport-apple verify signature is `(accessToken, refreshToken, idToken, profile, cb)`. The throw fires when the `idToken` argument is `undefined`, `null`, or `''`. This happens when Apple's callback omits `id_token` (misconfigured Service ID / Sign In with Apple not enabled for the client), when the strategy is invoked with a stale/replayed authorization code, or during local development where the Apple callback URL is hit directly or proxied incorrectly and the token never arrives.

Common situations: Apple Service ID misconfigured (domain/return URL mismatch in Apple Developer console), `APPLE_CALLBACK_URL` env pointing at the wrong route, running the callback behind a proxy that strips the POST body, or a `passport-apple` version change that altered the verify arity so the positional `idToken` lands in the wrong slot.

Related errors


AI-assisted analysis of danny-avila/LibreChat@5ff282f900 (2026-08-12). Data as JSON: /api/errors/2d5d9a5314a58456. Report an issue: GitHub.