Hello,
I have implemented Sign in with Apple in my iOS app and am currently trying to implement the revocation feature. However, I keep encountering an invalid_client error when calling the Apple authentication/revocation API.
Here are the details of my configuration:
Team ID: HUGD2H952H
Client ID: com.puppylink.puppylinkapp
Key ID: KXSYK98424
I am using these details to generate a client secret with the JWT ES256 algorithm. Below is the code I am using on the backend server to generate the client secret:
private fun makeClientSecret(): String {
val now: ZonedDateTime = ZonedDateTime.now(ZoneOffset.UTC)
val expirationTime: ZonedDateTime = now.plusMinutes(5) // Setting expiration time to 5 minutes
return Jwts.builder()
.setHeaderParam(JwsHeader.KEY_ID, appleProperties.keyId)
.setHeaderParam("alg", "ES256")
.setIssuer(appleProperties.teamId)
.setIssuedAt(Date.from(now.toInstant()))
.setExpiration(Date.from(expirationTime.toInstant()))
.setAudience("https://appleid.apple.com")
.setSubject(appleProperties.clientId)
.signWith(getPrivateKey(), SignatureAlgorithm.ES256)
.compact()
}
private fun getPrivateKey(): PrivateKey {
val resource = ClassPathResource(appleProperties.privateKeyFile)
val privateKey = String(Files.readAllBytes(Paths.get(resource.uri)))
val pemReader: Reader = StringReader(privateKey)
val pemParser = PEMParser(pemReader)
val converter = JcaPEMKeyConverter()
val keyInfo = pemParser.readObject() as PrivateKeyInfo
return converter.getPrivateKey(keyInfo)
}
}
Additionally, here is the code used to call the Apple authentication API from the backend server:
@Service
class AppleAuthService(
private val appleProperties: AppleProperties,
) {
private val logger = LoggerFactory.getLogger(javaClass)
private val restTemplate = RestTemplate()
fun getTokens(authorizationCode: String): TokenResponse {
try {
val clientSecret = makeClientSecret()
val formData: MultiValueMap<String, String> = LinkedMultiValueMap()
formData.add("client_id", appleProperties.clientId)
formData.add("client_secret", clientSecret)
formData.add("code", authorizationCode)
formData.add("grant_type", "authorization_code")
val headers = HttpHeaders()
headers.contentType = MediaType.APPLICATION_FORM_URLENCODED
val requestEntity = HttpEntity(formData, headers)
val response =
restTemplate.postForObject(
"https://appleid.apple.com/auth/token",
requestEntity,
TokenResponse::class.java,
)
return response ?: throw RuntimeException("Failed to retrieve tokens from Apple")
} catch (ex: Exception) {
logger.error("Error retrieving tokens: ", ex)
throw ex
}
}
data class TokenResponse(
val access_token: String,
val expires_in: Long,
val id_token: String,
val refresh_token: String,
val token_type: String,
)
Despite generating the client secret correctly, I am still receiving the invalid_client error when calling the API. Could you please help me identify the cause of this error and provide guidance on how to resolve it?
Thank you.