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
- Ensure clientSecret is the exact PEM text with real line breaks: -----BEGIN PRIVATE KEY----- ... -----END PRIVATE KEY-----
- If loading from env/secret store, use mechanisms that preserve newlines (e.g. base64-encode then decode, or multiline YAML block scalars)
- Confirm the bcpkix/bcprov (BouncyCastle) dependency is on the runtime classpath
- 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
- Base64-encode PEM secrets in env vars and decode at runtime to preserve newlines
- Verify bcpkix/bcprov are on the runtime classpath (esp. after fat-jar/shading)
- Test config loading with an actual JWT mint before deploying
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.