RocketChat/Rocket.Chat · error · Error
Could not retrieve Apple public keys
Error message
Could not retrieve Apple public keys
What it means
Thrown by getApplePublicKeys when fetching https://appleid.apple.com/auth/keys fails and there is no previously cached key set to fall back on. Apple's JWKS are required to verify Sign-in-with-Apple identityToken signatures. Keys are cached in-process for 24h and a stale cache is served if a refresh fails, so this error means the very first fetch (cold start) failed: outbound network to Apple is not working.
Source
Thrown at apps/meteor/server/lib/auth-providers/apple/handleIdentityToken.ts:59
// SECURITY: Hardcoded URL, no SSRF protection needed
ignoreSsrfValidation: true,
});
if (!response.ok) {
throw new Error(`Failed to fetch Apple keys: ${response.status} ${response.statusText}`);
}
const data = (await response.json()) as { keys: AppleJWK[] };
cachedKeys = data.keys;
lastFetchTime = now;
return cachedKeys;
} catch (error) {
if (cachedKeys) {
console.warn('Failed to refresh Apple public keys, using stale cache', error);
return cachedKeys;
}
throw new Error('Could not retrieve Apple public keys', { cause: error });
}
}
function decodeBase64Url(str: string): string {
return Buffer.from(str, 'base64url').toString('utf8');
}
async function verifyAppleJWT(
headerB64: string,
payloadB64: string,
signatureB64: string,
clientId: string,
): Promise<AppleJWTPayload | null> {
const header = JSON.parse(decodeBase64Url(headerB64));
const payload = JSON.parse(decodeBase64Url(payloadB64)) as AppleJWTPayload;
const nowInSeconds = Math.floor(Date.now() / 1000);
View on GitHub (pinned to b2c16d5842)
Solutions
- Allow outbound HTTPS to appleid.apple.com from the Rocket.Chat server process (proxy/allow-list/firewall)
- Configure the HTTP(S)_PROXY environment for the server so server-fetch reaches Apple
- Retry after connectivity is fixed; once one fetch succeeds, the 24h cache absorbs short Apple outages
Defensive patterns
Strategy: retry
Validate before calling
// pre-flight egress check at startup
try {
const res = await fetch('https://appleid.apple.com/auth/keys');
if (!res.ok) throw new Error(`Apple JWKS unreachable: ${res.status}`);
} catch (e) {
logger.error('Apple login will fail: no egress to appleid.apple.com', e);
} Try / catch
try {
const serviceData = await handleIdentityToken(identityToken, clientId);
} catch (e) {
if (e instanceof Error && e.message === 'Could not retrieve Apple public keys') {
// transient network / egress issue: inform user, retry with backoff; check e.cause
} else throw e;
} Prevention
- Allow-list outbound HTTPS to appleid.apple.com in firewalls/proxies for all Rocket.Chat nodes
- Monitor egress with a startup/periodic JWKS fetch so failures surface before users hit login
- Keep processes warm: once one fetch succeeds the 24h cache bridges short Apple outages
When it happens
Trigger: Apple OAuth login on a server with blocked internet egress (firewall/proxy/DNS) so the JWKS fetch throws or returns non-200; Apple endpoint temporarily unavailable during a cold start; proxy misconfiguration stripping the request; TLS interception breaking the connection.
Common situations: Self-hosted instances in air-gapped or egress-restricted networks; containers without proxy env vars; on-prem installs where only specific domains are allow-listed and appleid.apple.com is missing.
Related errors
- Failed to refresh Apple public keys, using stale cache
- Malformed identityToken: JWT must have 3 parts
- identityToken is not a valid Apple JWT or has expired
- Insufficient data: Missing subject (sub) in auth response to
- App package download failed
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/d1cea9f8bffb8bf6.
Report an issue: GitHub.