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