I’m writing a server application that handles Apple ID authorization from the iOS device.
The server is written in C# .net ASP.NET framework.
To authenticate I’m using this data:
_config.ClientId=com.organization.ios.app_name,_config.PrivateKeyId– .p8 file key id_config._DevelopmentTeam– code located before client id name ,X.com.organization.ios.app_namethat X,_config.PrivateKey– private key from .p8 file
From request from an iOS device I’m getting:
request.AuthCode– authorization code,request.IdentityToken– token.
Code is really simple:
public Task<ResponseDTO> AuthenticateWithApple(RequestDTO request)
{
var contentData = new List<KeyValuePair<string, string>>()
{
new KeyValuePair<string, string>("client_id", _config.ClientId),
new KeyValuePair<string, string>("client_secret", GenerateAppleJwtToken()),
new KeyValuePair<string, string>("code", passData.AuthCode);
new KeyValuePair<string, string>("grand_type", "authorization_code"),
new KeyValuePair<string, string>("refresh_token", "");
new KeyValuePair<string, string>("redirect_uri", "");
};
try
{
var content = new FormUrlEncodedContent(contentData);
var response = await httpClient.PostAsync(_requestUrl, content);
var rawResponseData = await response.Content.ReadAsStringAsync();
if (response.StatusCode == HttpStatusCode.OK)
{
var responseData = JsonConvert.DeserializeObject<ResponseDTO>(rawResponseData);
return responseData;
}
else
{
var errorMessage = $"Status code {response.StatusCode}: "{rawResponseData}"";
throw new ArgumentException(errorMessage);
}
}
catch (Exception exc)
{
var error = new ErrorResponseViewModel();
var errorMessage = $"Problem encountered during authorization: {exc.Message}";
error.AddError(ErrorTypes.UNAUTHORIZED, nameof(AppleAuthenticationProvider), errorMessage);
return new ResponseDTO()
{
Errors = error
};
}
}
And for creating JWT client secret code is:
private string GenerateAppleJwtToken()
{
var issueTime = DateTime.Now;
var zeroTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
var iat = (int) issueTime.Subtract(zeroTime).TotalSeconds;
var exp = (int) issueTime.AddMinutes(5).Subtract(zeroTime).TotalSeconds;
var headers = new Dictionary<string, object>()
{
{ "alg", "ES256" },
{ "typ", "JWT" },
{ "kid", _config.PrivateKeyId },
};
var payload = new Dictionary<string, object>()
{
{ "sub", _config.ClientId },
{ "aud", "https://appleid.apple.com" },
{ "iss", _config.DevelopmentTeam },
{ "exp", exp },
{ "iat", iat }
};
var cngKey = CngKey.Import(Convert.FromBase64String(_config.PrivateKey), CngKeyBlobFormat.Pkcs8PrivateBlob);
var ecdsa = new ECDsaCng(cngKey);
byte[] headerBytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(headers, Formatting.None));
byte[] claimsBytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(payload, Formatting.None));
var base64Payload = Base64UrlEncoder.Encode(headerBytes) + "." + Base64UrlEncoder.Encode(claimsBytes);
var signature = ecdsa.SignData(Encoding.UTF8.GetBytes(base64Payload), HashAlgorithmName.SHA256);
return base64Payload + "." + Base64UrlEncoder.Encode(signature);
}
According to many code implementations of Apple ID authorization, this should work, but it doesn’t.
Error message is that i recive is: “unsupported_grant_type”
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
You are sending a parameter grand_type, but grant_type is expected. Mind the typo in grand.
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0