SignIn With Apple "invalid_client" error Asp.Net Core token request

1.1k Views Asked by At

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.

  1. Create App ID with signin with apple

  2. with Sign In With Apple enabled

  3. Creating service identifier with Sign In With Apple enabled

  4. Create key for this app

  5. 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:

enter image description here

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.

1

There are 1 best solutions below

0
Anton Koposov On

The magic was to add this

SigningCredentials = new SigningCredentials(new ECDsaSecurityKey(ecdsa){KeyId = keyId},
SecurityAlgorithms.EcdsaSha256)

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 keyId for Apple to recognize the key for validation.