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
- 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.
- 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.
- 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.
- 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
- Validate all APPLE_* env vars at startup and fail fast if any are unset when Apple Sign-In is enabled.
- Log the arity/values of the passport-apple verify callback during integration to catch positional mismatches early.
- Register the exact Return URL in the Apple Developer console and run an end-to-end test login before shipping.
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
- Failed to authenticate OAuth tool
- [MCP][${serverName}][${toolName}] upstream authentication fa
- [MCP][${serverName}][${toolName}] OAuth authentication requi
- User must be authenticated via OpenID to perform OBO token e
- OAuth flow not found
AI-assisted analysis of danny-avila/LibreChat@5ff282f900 (2026-08-12).
Data as JSON: /api/errors/2d5d9a5314a58456.
Report an issue: GitHub.