I`m trying to implement Sign In With Apple in my Asp.Net Core application using OpenIdConnect client library. With help of this article https://www.scottbrady91.com/openid-connect/implementing-sign-in-with-apple-in-aspnet-core. Everything works fine when I create application in apple console https://developer.apple.com/account/resources/identifiers. But when I create another application (and service identifier with corresponding key) the new application doesnt work.
Creating service identifier with Sign In With Apple enabled
Create key for this app
Use this key for client_secret generation
If I create another app/serviceId/key it doesnt work untill I revoke key for first app and create new key for new app.
How can I create two working apps? I there any restriction?
Adding "apple" external provider:
.AddOpenIdConnect("apple", async options =>
{
options.ResponseType = "code id_token"; // hybrid flow due to lack of PKCE support
options.ResponseMode = "form_post"; // form post due to prevent PII in the URL
options.UsePkce = false; // apple does not currently support PKCE (April 2021)
options.DisableTelemetry = true;
options.Scope.Clear(); // apple does not support the profile scope
options.Scope.Add("openid");
options.Scope.Add("email");
options.Scope.Add("name");
options.Authority = "https://appleid.apple.com";
options.ClientId = configuration["Authentication:Apple:ClientId"]; // Service ID
options.CallbackPath = "/signin-apple";
options.Events.OnAuthorizationCodeReceived = context =>
{
context.TokenEndpointRequest.ClientSecret = AppleTokenGenerator.CreateNewToken(configuration["Authentication:Apple:Iss"],configuration["Authentication:Apple:ClientId"], configuration["Authentication:Apple:ClientSecret"]);
return Task.CompletedTask;
};
// TODO
})
Generating client_secret as described in https://www.scottbrady91.com/openid-connect/implementing-sign-in-with-apple-in-aspnet-core.:
public static string CreateNewToken(string iss, string sub, string privateKey)
{
const string aud = "https://appleid.apple.com";
var now = DateTime.UtcNow;
var ecdsa = ECDsa.Create();
ecdsa?.ImportPkcs8PrivateKey(Convert.FromBase64String(privateKey), out _);
var handler = new JsonWebTokenHandler();
return handler.CreateToken(new SecurityTokenDescriptor
{
Issuer = iss,
Audience = aud,
Claims = new Dictionary<string, object> { { "sub", sub } },
Expires = now.AddMinutes(60), // expiry can be a maximum of 6 months - generate one per request or re-use until expiration
IssuedAt = now,
NotBefore = now.AddMinutes(-60),
SigningCredentials = new SigningCredentials(new ECDsaSecurityKey(ecdsa), SecurityAlgorithms.EcdsaSha256)
});
}
Authorization request works fine. No errors and redirecting browser to options.CallbackPath = "/signin-apple";
Error occures on token request: OpenIdConnectProtocolException: Message contains error: 'invalid_client', error_description: 'error_description is null', error_uri: 'error_uri is null'.
I`ve simulated request:
curl --location --request POST 'https://appleid.apple.com/auth/token?grant_type=authorization_code&client_id=ua.secret.site&code=c3a55f910698647768b41e76a80881778.0.rwqy.Pt5lhGYR0eKHHmIOhsrkrw&redirect_uri=https://local.test:5001/signin-apple&client_secret=eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1YS5zZWNyZXQuc2l0ZSIsImF1ZCI6Imh0dHBzOi8vYXBwbGVpZC5hcHBsZS5jb20iLCJleHAiOjE2NTQwOTg2NjYsImlzcyI6IjdCNjREQzJYUE4iLCJpYXQiOjE2NTQwOTUwNjYsIm5iZiI6MTY1NDA5MTQ2Nn0.PkaPgnCF4u53w9yZgRXqmJ1xyN2DhTIukoknvRQ0jLfU4riVEUqPwh5c0Umx_cteadrcTjID-J_iH3hFPxUTrA'
and getting this response:
{
"error": "invalid_client"
}
with no usefull response headers
But with another client everything is ok

Also I`ve made experiment releasing and revoking keys for two different applications (t - testing app, p - production app). Here is the result:
Conclusion: Only one of two keys is working at a time, despite being created for diferent applications. Keys are being invalidated acording to key rotation rules for SINGLE application (https://help.apple.com/developer-account/?lang=en#/dev77c875b7e), but sometimes NOT. I`am so confused.

The magic was to add this
It works fine when there is one key, but if there are multiple, I guess it uses the last key for validation. You need to add
keyIdfor Apple to recognize the key for validation.