public static AppleAccount FromUrl(string url) { var parameters = Util.ParseUrlParameters(url); var idToken = JwtToken.Decode(parameters["id_token"]); return(new AppleAccount { IdToken = idToken, UserId = idToken.Subject, Email = idToken.Payload.ContainsKey("email") ? idToken.Payload["email"]?.ToString() : null, Name = idToken.Payload.ContainsKey("name") ? idToken.Payload["name"]?.ToString() : null, AccessToken = parameters.ContainsKey("access_token") ? parameters["access_token"] : null, RefreshToken = parameters.ContainsKey("refresh_token") ? parameters["refresh_token"] : null, }); }
public async Task <AppleAccount> ExchangeTokenAsync(string code) { var client = new HttpClient(); var header = new ProductHeaderValue("Xamarin", "1.0"); var userAgentHeader = new ProductInfoHeaderValue(header); client.DefaultRequestHeaders.UserAgent.Add(userAgentHeader); var secret = GenerateClientSecretJWT(P8FileContents); var resp = await client.PostAsync(AppleTokenUrl, new FormUrlEncodedContent(new Dictionary <string, string> { { "grant_type", "authorization_code" }, { "code", code }, { "redirect_uri", RedirectUri.OriginalString }, { "client_id", ServerId }, { "client_secret", secret }, })); resp.EnsureSuccessStatusCode(); var respData = await resp.Content.ReadAsStringAsync(); var respProperties = Newtonsoft.Json.JsonConvert.DeserializeObject <Dictionary <string, string> >(respData); var idToken = JwtToken.Decode(respProperties["id_token"]); var accessToken = respProperties?["access_token"]; var refreshToken = respProperties?["refresh_token"]; string email = idToken.Payload.ContainsKey("email") ? idToken.Payload["email"]?.ToString() : null; string name = idToken.Payload.ContainsKey("name") ? idToken.Payload["name"]?.ToString() : null; if (name == null) { try { JObject obj = JObject.Parse(respData); name = obj["user"]["name"]["firstName"].ToString() ?? null; } catch (Exception ex) { name = null; } } // Validate id token if (!idToken.Issuer.Equals(AppleJwtUrl)) { throw new ProtocolViolationException($"Invalid id_token issuer received: Expected `{AppleJwtUrl}` but observed `{idToken.Issuer}`"); } if (!idToken.AccessTokenHash.Equals(Util.Sha256AtHash(accessToken))) { throw new ProtocolViolationException("Access Token Hash did not match actual access token's hash"); } if (!idToken.Algorithm.Equals("RS256")) { throw new ProtocolViolationException($"Invalid id_token algorithm returned: Expected `RS256` but observed `{idToken.Algorithm}`"); } // Verify audience claim if (!idToken.Audience.Equals(ServerId)) { throw new ProtocolViolationException($"The id_token 'aud' claim does not match the provided clientId value.") ; } if (idToken.Expiration < DateTime.UtcNow) { throw new ProtocolViolationException($"The id_token is expired"); } // TODO: Verify the signature of the JWT token return(new AppleAccount { Email = email, Name = name, AccessToken = accessToken, RefreshToken = refreshToken, IdToken = idToken }); }