I am working on Receipt Validation for a subscription In App Purchase for my application. I am Using SwiftyReceiptValidator files from this github project:
https://github.com/crashoverride777/SwiftyReceiptValidator/tree/master/SwiftyReceiptValidator
to help me with my receipt validation.
in my code I'm using:
SwiftyReceiptValidator.validate(forIdentifier: "MyProductId", sharedSecret: "MyCorrectSharedSecret") { (bool: Bool, dict: [String : AnyObject]?) in
}
when I try to validate my product I'm getting status = 21004 which means incorrect SharedSecret Key. But I am 100% sure that my Shared Secret is correct as I copied and pasted it directly from itunes connect.
Question:
Is This error for sure caused by SharedSecret Key? Or could this be caused by something else?
Output when executing the code above
Receipt found
Starting receipt validation
Receipt validation failed: URL request - Invalid receipt status in json response = 21007
Receipt validation failed: Production url used in sandbox mode, trying sandbox url...
Receipt validation failed: URL request - Invalid receipt status in json response = 21004
Receipt validation failed: Status = 21004
It seems to be fixed right now
https://forums.developer.apple.com/thread/72991
Related
Look like apple is making any type of update this month.... recently my app was rejected with this message
When validating receipts on your server, your server needs to be able
to handle a production-signed app getting its receipts from Apple’s
test environment. The recommended approach is for your production
server to always validate receipts against the production App Store
first. If validation fails with the error code "Sandbox receipt used
in production," you should validate against the test environment
instead.
My app was approved before ... this is the code that i m using
//Sandbox URL
//let url = URL(string: "https://sandbox.itunes.apple.com/verifyReceipt")!
let url = URL(string: "https://buy.itunes.apple.com/verifyReceipt")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = bodyData
let task = URLSession.shared.dataTask(with: request) { (responseData, response, error) in
if let error = error {
completion(.failure(.other(error)))
} else if let responseData = responseData {
let json = try! JSONSerialization.jsonObject(with: responseData, options: []) as! Dictionary<String, Any>
//print(json)
let session = Session(receiptData: data, parsedReceipt: json)
self.sessions[session.id] = session
let result = (sessionId: session.id, currentSubscription: session.currentSubscription)
completion(.success(result))
}
}
task.resume()
}
You don't have to use a server. You can validate it on the client if you want. Or you could completely forgo any validation if you wanted (not recommended).
The rejection you are getting is most likely because this time around, they used a test env to validate IAP.
Their documentation states
If you are doing receipt validation, be sure to verify your receipt
with the production URL (https://buy.itunes.apple.com/verifyReceipt)
first. This applies even in the case where your app is used in the
sandbox environment. App Review will review the production version of
your app in the sandbox. When your app processes the receipt, it must
be capable of detecting the 21007 receipt status code and sending the
receipt to the sandbox receipt validation server
(https://sandbox.itunes.apple.com/verifyReceipt). Once your app is
approved and running in the production environment, sending the
receipt to the production server first is the correct action.
Notice that they don't specify where the receipt validation is done.
What your code lacks is the fallback to the sandbox. Hence why they rejected you this time around.
I am using Twilio's latest SDK they released on CocoaPods as of today. I am trying to implement VOIP feature to my app with Twilio Programmable Voice. My backend is .net which also uses the latest release of Twilio Helper Library for C#.
My client code looks like:
fetchAccessToken { (accessToken: String) in
TwilioVoice.register(withAccessToken: accessToken, deviceToken: deviceToken) { (error) in
if let error = error {
NSLog("An error occurred while registering: \(error.localizedDescription)")
}
else {
NSLog("Successfully registered for VoIP push notifications.")
}
}
}
What I get in the console is as following:
voipTestWithTwilio[2431:517236] [ERROR TwilioVoice] Inside register:deviceToken:completion:, failed to register for Twilio push notifications. Error:Invalid access token signature
voipTestWithTwilio[2431:517236] An error occurred while registering: Invalid access token signature
This is the C# code that actually creates the token:
var grant = new VoiceGrant
{
OutgoingApplicationSid = outgoingApplicationSid
};
var grants = new HashSet<IGrant> { { grant } };
var token = new Token(
accountSid: accountSid,
signingKeySid: apiKey,
secret: apiSecret,
identity: identity,
grants: grants
);
return token.ToJwt();
I have been looking for the issue on the internet, nothing helped so far. I have tried contacting them but have not got any response back. I also tried creating new api keys and even a new project for a couple times on Twilio. Can anybody say something about the issue?
UPDATE
I added push notification sid to VoiceGrant and now I’m getting 403 Forbidden.
On Twilio error codes page it is explained as: “The expiration time provided in the Access Token exceeds the maximum duration allowed.” which is definitely not my case. However, I tried passing expiration parameter in Token constructor with various values which didn’t change the result.
The problem is still persisting.
I solved the issue. It was because my server returned the token with quotation mark.
I remember print(token)'ing on client (iOS) to see whether there is encoding issue or something and all I see was a proper token between quotation marks. Since token is a string value, I didn't pay attention to quotation part of it. That's where I was wrong.
I'm trying to verify the receipt for an in app purchase with my own node server. I used the information available on this page:
https://developer.apple.com/library/content/releasenotes/General/ValidateAppStoreReceipt/Chapters/ValidateRemotely.html
I send the receipt-data in a base64 encoded string as the value of the key receipt data. But everytime I get the Status 21002 which means that the receipt-data property if malformed or missing.
Im using the request module for node to send the request and this is what my code looks like:
var payload = {
"receipt-data":receipt_data,
"password":password
}
request.post(
config.appStoreReceiptVerificationUrl,
{
form:payload
},
function(err, response, data_str)
{// handle response here}
This is the data in the receipt_data variable: http://textuploader.com/d0tup
What could be the problem?
I have some rails code which get's an in-app purchase receipt from Apple and verifies it towards either sandbox or production. This has worked fine, but as of lately I am seeing some 21002 (The data in the receipt-data property was malformed) errors in my logs. I can see these are from apps in production.
Below is my RoR code that verifies the receipt, do you see anything that would cause a 21002?
Thanks so much!
def verifyReceipt (receipt_data)
# Checking the magazine status to get the proper verification url
if Publication.find_by_app_id(params[:app_id]).development_mode
logger.info "Sandbox mode detected"
url = "https://sandbox.itunes.apple.com/verifyReceipt"
else
logger.info "Production mode detected"
url = "https://buy.itunes.apple.com/verifyReceipt"
end
# Get the magazines shared secret
shared_secret = Publication.where("app_id = ?", params[:app_id]).first.itunes_shared_secret
if shared_secret.nil? or shared_secret.blank?
# Invalid magazine
logger.info "Shared secret does not exist or does not match iTunes shared secret!"
result = false
else
logger.info "Verifying receipt from Apple now!"
# Verify receipt with apple based on magazine status, and save results
data = { "receipt-data" => receipt_data, "password" => shared_secret }
request = Typhoeus::Request.new(url, method: :post, body: data.to_json )
request.run
result = JSON.parse(request.response.body).with_indifferent_access
logger.info "Result from verification: #{result[:status]}"
end
return result
end
If it is on production, it is a normal behavior to get 21002 errors some times.
The major cause is someone use JB device or IAP cracker on your native app and try to do a fake purchase. The fake receipt failed in the AppStore validation and a 21002 error is returned.
You may do a formal purchase to make sure everything works well in case.
How can I check purchase id which was sent by user to me from his orders list?
For example, he can send something like: M1VYXX7VX7 (as written in his purchases list in appstore) and ask to return his purchase (may be he had deleted his app accidentally),
But when I get order information inside of my code (through SKPaymentTransaction) I have no access to that identifier. Then only ID i have looks like: 1000000020706713.
So is there any ways to validate that purchase ID using information which was sent to me by app store?
Thanks.
Read Verifying Store Receipts in the In-App Purchase Programming Guide. According to the documentation:
To verify the receipt, perform the following steps:
Retrieve the receipt data. On iOS, this is the value of the transaction's transactionReceipt property. On OS X, this is the entire contents of the receipt file inside the application bundle. Encode the receipt data using base64 encoding.
Create a JSON object with a single key named receipt-data and the string you created in step 1. Your JSON code should look like this:
{
"receipt-data" : "(receipt bytes here)"
}
Post the JSON object to the App Store using an HTTP POST request. The URL for the store is https://buy.itunes.apple.com/verifyReceipt.
The response received from the App Store is a JSON object with two keys, status and receipt. It should look something like this:
{
"status" : 0,
"receipt" : { (receipt here) }
}
If the value of the status key is 0, this is a valid receipt. If the value is anything other than 0, this receipt is invalid.
Read the article for more details.