Integrating singin with apple with Identity Server 4

Viewed 756

I spent some time figuring out how to make Sign-in With Apple work with identity Server and here are the steps to follow. I will improve the answer when I get time next time.

1 Answers

Update your startup.cs configure Services method to support signing with Apple.

services.AddAuthentication(auth =>
            {
                auth.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                auth.DefaultSignInScheme = ProviderSchemaConstants.Apple;
            }).AddOpenIdConnect(ProviderSchemaConstants.Apple, ProviderDisplayNameConstants.Apple,  async options =>
                {
                    options.ClientId = this.Configuration["SignInWithApple:ClientId"];
                    options.ResponseType = "code";
                    options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
                    options.SignOutScheme = IdentityServerConstants.SignoutScheme;
                    options.DisableTelemetry = true;
                    options.CallbackPath = "/signin-apple";
                    options.Scope.Clear();
                    options.Scope.Add("email");
                    options.Scope.Add("name");
                    options.Configuration = new OpenIdConnectConfiguration
                    {
                        AuthorizationEndpoint = "https://appleid.apple.com/auth/authorize",
                        TokenEndpoint = "https://appleid.apple.com/auth/token"
                    };
                    options.Events.OnAuthorizationCodeReceived = context =>
                    {
                        context.TokenEndpointRequest.ClientSecret = this.CreateNewToken();
                        return Task.CompletedTask;
                    };

                    options.TokenValidationParameters.ValidIssuer = "https://appleid.apple.com";
                    var jwks = await new HttpClient().GetStringAsync("https://appleid.apple.com/auth/keys");
                    options.TokenValidationParameters.IssuerSigningKeys = new JsonWebKeySet(jwks).Keys;
                    options.ProtocolValidator.RequireNonce = false;
                });

Add this method to the bottom of Startup.cs or in a separate file.

 private string CreateNewToken()
        {
            try
            {
                const string iss = "ACCOUNT_ID_NEED_TO_BE_REPLACED"; // your account's team ID found in the dev portal
                const string aud = "https://appleid.apple.com";
                const string sub = "CLIENTNAME_FROM_APPLE_DEVELOPER_PORTAL"; // same as client_id

                // var fileInfo = await System.IO.File.ReadAllBytesAsync(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "AuthKey_KEYID_NEED_TO_BE_REPLACeD.p8"));
                const string privateKey = "KEY_NEED_TO_BE_REPLACED"; // contents of .p8 file
                var cngKey = CngKey.Import(
                    Convert.FromBase64String(privateKey),
                    CngKeyBlobFormat.Pkcs8PrivateBlob);
                var d = DateTime.UtcNow.AddDays(-5);

                var handler = new JwtSecurityTokenHandler();
                var token = handler.CreateJwtSecurityToken(
                    issuer: iss,
                    audience: aud,
                    subject: new ClaimsIdentity(new List<Claim> { new Claim("sub", sub) }),
                    expires: d.AddMonths(3), // expiry can be a maximum of 6 months
                    issuedAt: d,
                    notBefore: d,
                    signingCredentials: new SigningCredentials(
                        new ECDsaSecurityKey(new ECDsaCng(cngKey)), SecurityAlgorithms.EcdsaSha256));

                return handler.WriteToken(token);
            }
            catch (Exception exception)
            {
                throw exception;
            }
        }

Please let me know if you need help anywhere, I can add more info.

Related