justauth/JustAuth · error · AuthException

Failed to get apple private key

Error message

Failed to get apple private key

What it means

AuthException('Failed to get apple private key') thrown from AuthAppleRequest.getPrivateKey when parsing config.getClientSecret() as a PEM fails with IOException. The .p8 content is fed to BouncyCastle's PEMParser, cast to PrivateKeyInfo — anything that is not an EC private key in PKCS#8 PEM form triggers this (the IOException is chained).

Source

Thrown at src/main/java/me/zhyd/oauth/request/AuthAppleRequest.java:137

            .issuer(this.config.getTeamId())
            .subject(this.config.getClientId())
            .audience().add(AUD).and()
            .expiration(new Date(System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(3)))
            .issuedAt(new Date())
            .signWith(getPrivateKey())
            .compact();
    }

    private PrivateKey getPrivateKey() {
        if (this.privateKey == null) {
            synchronized (this) {
                if (this.privateKey == null) {
                    try (PEMParser pemParser = new PEMParser(new StringReader(this.config.getClientSecret()))) {
                        JcaPEMKeyConverter pemKeyConverter = new JcaPEMKeyConverter();
                        PrivateKeyInfo keyInfo = (PrivateKeyInfo) pemParser.readObject();
                        this.privateKey = pemKeyConverter.getPrivateKey(keyInfo);
                    } catch (IOException e) {
                        throw new AuthException("Failed to get apple private key", e);
                    }
                }
            }
        }
        return this.privateKey;
    }

    @Data
    static class AppleUserInfo {
        private AppleUsername name;
        private String email;
    }

    @Data
    static class AppleUsername {
        private String firstName;
        private String lastName;
    }

View on GitHub (pinned to 694bbf1b01)

Solutions

  1. Ensure clientSecret is the exact PEM text with real line breaks: -----BEGIN PRIVATE KEY----- ... -----END PRIVATE KEY-----
  2. If loading from env/secret store, use mechanisms that preserve newlines (e.g. base64-encode then decode, or multiline YAML block scalars)
  3. Confirm the bcpkix/bcprov (BouncyCastle) dependency is on the runtime classpath
  4. Inspect the chained IOException message — 'recognised object type' or class-cast errors indicate wrong key material or PEM structure

Example fix

// before
String key = System.getenv("APPLE_KEY"); // flattened to one line with literal \n
// after
String key = new String(Base64.getDecoder().decode(System.getenv("APPLE_KEY_B64")), StandardCharsets.UTF_8);
// key now contains real newlines and full PEM headers
Defensive patterns

Strategy: validation

Validate before calling

String pem = config.getClientSecret();
boolean looksLikePem = pem != null && pem.contains("-----BEGIN PRIVATE KEY-----")
    && pem.contains("\n") && pem.contains("-----END PRIVATE KEY-----");
if (!looksLikePem) {
    throw new IllegalStateException("APPLE clientSecret is not a valid .p8 PEM (missing headers or newlines)");
}

Type guard

private static boolean isValidAppleP8(String pem) {
    return pem != null
        && pem.startsWith("-----BEGIN PRIVATE KEY-----")
        && pem.endsWith("-----END PRIVATE KEY-----")
        && pem.contains("\n");
}

Try / catch

try {
    AuthUser u = appleRequest.getUserInfo(token);
} catch (AuthException e) {
    if ("Failed to get apple private key".equals(e.getMessage())) {
        // config bug, not runtime — check PEM format & BouncyCastle on classpath
        throw new IllegalStateException("Apple .p8 config invalid; see cause", e.getCause());
    }
    throw e;
}

Prevention

When it happens

Trigger: clientSecret containing a file path instead of PEM content, escaped \n instead of real newlines, a truncated key, a wrong key type (RSA PEM or a public key), or BouncyCastle PEMParser missing from the classpath causing the try-with-resources to fail.

Common situations: Reading the .p8 from an env var where newlines were flattened; YAML/JSON config stripping or escaping the multiline PEM; pasting an APNs-style key without the BEGIN/END lines; shading/trimming dependencies so bcpkix is absent.

Related errors


AI-assisted analysis of justauth/JustAuth@694bbf1b01 (2026-08-14). Data as JSON: /api/errors/ef53d5d5cf1ec21f. Report an issue: GitHub.