RocketChat/Rocket.Chat · warning
Failed to refresh Apple public keys, using stale cache
Error message
Failed to refresh Apple public keys, using stale cache
What it means
To verify Sign in with Apple identity tokens, the server fetches Apple's JWKS from https://appleid.apple.com/auth/keys; the fetch failed (network error or non-OK HTTP status). If a previously fetched key set is cached, it is returned as a stale cache and logins continue with the old keys; with no cache the function throws 'Could not retrieve Apple public keys' and Apple sign-in fails entirely.
Source
Thrown at apps/meteor/server/lib/auth-providers/apple/handleIdentityToken.ts:56
try {
const response = await fetch('https://appleid.apple.com/auth/keys', {
method: 'GET',
// 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;View on GitHub (pinned to b2c16d5842)
Solutions
- Allow outbound HTTPS to appleid.apple.com from the Rocket.Chat server
- Behind TLS-inspecting proxies, set HTTPS_PROXY and NODE_EXTRA_CA_CERTS so the fetch succeeds
- If logins fail with 'Could not retrieve Apple public keys', the cache was empty — fix egress before anything else
- No urgent action while logins still work: stale keys are valid until Apple rotates; monitor for the throwing variant
Defensive patterns
Strategy: fallback
Validate before calling
// health check: verify egress to Apple's JWKS endpoint before enabling Sign in with Apple
const res = await fetch('https://appleid.apple.com/auth/keys');
if (!res.ok) throw new Error(`Apple JWKS unreachable: ${res.status}`); Try / catch
try {
return await fetchAppleKeys();
} catch (error) {
if (cachedKeys) {
console.warn('Failed to refresh Apple public keys, using stale cache', error);
return cachedKeys; // valid until Apple rotates its signing key
}
throw new Error('Could not retrieve Apple public keys', { cause: error });
} Prevention
- Allowlist outbound HTTPS to appleid.apple.com in firewall/proxy rules
- Set NODE_EXTRA_CA_CERTS/HTTPS_PROXY when behind TLS inspection
- Alert on repeated warns: stale-cache mode ends the moment Apple rotates keys, breaking all Apple logins
When it happens
Trigger: Outbound HTTPS to appleid.apple.com blocked by firewall/proxy; Apple endpoints returning non-200; TLS interception with a CA Node does not trust; DNS failures. Apple logins keep working on stale keys until Apple rotates its signing key.
Common situations: Locked-down servers without an egress allowlist entry for appleid.apple.com; corporate proxies requiring custom CAs (missing NODE_EXTRA_CA_CERTS); transient Apple outages observed as repeated warns with successful fallback.
Related errors
- Could not retrieve Apple public keys
- could-not-access-webdav
- Failed to complete OAuth handshake with ${this.name} at ${th
- The user for app ${appId} is not registered.
- Invalid OAuth client
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/5a07daabaf63d7c5.
Report an issue: GitHub.