How to use Uber iOS SDK API in sandbox environment? - uber-api

I know how to use Uber-API in sandbox environment :
https://sandbox-api.uber.com/<version>
But i am not able to find how to use iOS SDK API in sandbox environment. This is piece of code from Uber developer doc...
ridesClient.requestRide(parameters: builder.build(), completion: { ride, response in
guard let ride = ride else {
// Handle error, unable to request ride
return
}
// Ride has been requested!
})
So, how would i know if this request is for real or sandbox environment?

There is a Configuration singleton class that has a property isSandbox that you can set to true. The default is false.
Configuration.shared.isSandbox = true

Related

Can you use App Store Sandbox testing (verifyReceipt specifically) before submitting the app or the related IAPs?

I've been trying to use the verifyReceipt endpoint to verify in-app purchase transactions with no success.
Here's how I'm doing it.
1. Read the receipt data in iOS (this is copy paste from Apple's documentation):
if let appStoreReceiptURL = Bundle.main.appStoreReceiptURL,
FileManager.default.fileExists(atPath: appStoreReceiptURL.path) {
do {
let receiptData = try Data(contentsOf: appStoreReceiptURL, options: .alwaysMapped)
print(receiptData)
let receiptString = receiptData.base64EncodedString(options: [])
// sendReceiptToBackEnd(receiptString)
}
catch { print("Couldn't read receipt data with error: " + error.localizedDescription) }
}
2. In the backend, I followed this advice from Apple:
As a best practice, always call the production URL for verifyReceipt first, and proceed to verify with the sandbox URL if you receive a 21007 status code.
So first I try this (python code):
data = {
'receipt-data': receipt_string, # this is what we get from the frontend
'password': settings.APP_STORE_SHARED_SECRET
}
url = 'https://buy.itunes.apple.com/verifyReceipt'
response = requests.post(url, json=data)
response_data = response.json()
status = response_data['status']
Status here is 21007, which is expected according to the advice above. So then I try the sandbox:
url = 'https://sandbox.itunes.apple.com/verifyReceipt'
response = requests.post(url, json=data)
response_data = response.json()
status = response_data['status']
And I get 21002 - which means there's probably something wrong with what I sent.
Initially I was trying to test this using Xcode locally, but I found out later that verifyReceipt doesn't work with this feature because app's are not signed by the App Store. So I deleted the local configs and set the StoreKit Configuration in scheme back to none, and verified the app is using the App Store Connect as it was picking up any changes I made there in the price.
I'm out of ideas on how to debug this further, so I'm wondering could it be because the App & IAPs are not submitted yet? Currently the app is in the "Prepare for Submission" state, and the IAPs are in the "Ready to Submit" state. Or maybe there is something else I'm missing?
Edit: The answer to my question is "yes, you can." I copied and pasted the json and sent it manually using Postman and it worked fine so something is happening in the backend. I'm leaving the question for reference but if someone recommends deleting please let me know.
I saw your edit, but just as a follow-up code 21002 is a "malformed body" response (or theoretically an Apple server issue, but I've only seen it when mangling the receipt data).
You can see the full list of codes and meanings here:
https://developer.apple.com/documentation/appstorereceipts/status
Incidentally, as you build our your server to process iTunes responses you may find this guide useful for processing the receipt on the server:
https://www.namiml.com/blog/app-store-verify-receipt-definitive-guide

Calling Google Sheets API in Swift with GTMAppAuth

I'm trying to read/write to Google Sheets in Swift on macOS.
I'm using the GAppAuth library which in turn makes use of GTMAppAuth.
I managed to get authorized and get back both the access token and the refresh token but I still get an HTTP status code of 403 when I try to make a call to one of the Google Sheets' endpoints.
In applicationDidFinishLaunching(_:) I appended the following authorization scope, as detailed in the documentation:
GAppAuth.shared.appendAuthorizationRealm("https://www.googleapis.com/auth/spreadsheets.readonly")
But still, I get 403. What am I doing wrong? Am I adding the scope properly?
This is the code where I make the API call:
#IBAction func getSpreadsheet(_ sender: NSButton) {
let fetcherService = GTMSessionFetcherService()
fetcherService.authorizer = authorization
let spreadsheetInfo = URL(string: "https://sheets.googleapis.com/v4/spreadsheets/{spreadsheetID}")
let fetcher = GTMSessionFetcher(url: spreadsheetInfoEndpoint)
fetcher.beginFetch { (data, error) in
//Error code 403
}
}
I got it working by looking at the cURL request with the Google API Explorer. The access token parameter was missing:
https://sheets.googleapis.com/v4/spreadsheets/[SPREADSHEETID]/values/[RANGE]?access_token=[access_token]
Also thanks to Jacques-Guzel Heron, in the comment section, who let me know of the official Google Auth Library for Swift. I'll check it out.

iOS Today Widget utilize Uber login token

I have an app with an Uber login that gives access to restricted API calls (info on the current ride). I'd like to share the login token with the associated Today Widget so it can make similar calls.
I'm already sharing data with a UserDefaults suite, and I'm using the UberRides SDK. In digging into the RidesClient object it seems to try to use the keychain for storing/sharing the login token, and I set up a shared keychain to try to take advantage of this, but no luck. Restricted API calls from the widget return as unauthorized. Any suggestions?
Here's some code from the widget (note the user already authenticated in the main app):
let rc = RidesClient()
rc.fetchCurrentRide { ride, response in
if ride == nil { print("NO CURRENT RIDE") }
print(response.response)
print(response.error?.title)
if let ride = ride {
// do something
} else {
self.ride = nil
}
}
This returns an unauthorized response. I traced into the RidesClient (which is an object in the UberRides SDK), and see the code where the token is "supposed" to come from the keychain, but it doesn't.
I also tried generating my own URL request in the widget, using the login token passed through shared UserDefaults. This followed the standard HTTP access approach, putting the token in the Authorization header. But I got the same unauthorized response.
Here's some more details on the SDK approach:
Main app uses the LoginButton in native mode:
let scopes: [RidesScope] = [.Profile, .Places, .Request, .AllTrips]
let loginManager = LoginManager(accessTokenIdentifier: Configuration.getDefaultAccessTokenIdentifier(), keychainAccessGroup: "com.MYCOMPANY.MYAPP.share", loginType: .native)
let loginButton = LoginButton(frame: loginFrame, scopes: scopes, loginManager: loginManager)
loginButton.presentingViewController = self
loginButton.delegate = self
view.addSubview(loginButton)
The login button does the right thing and authorizes in the Uber app. I can see the token returned in the delegate callback didCompleteLoginWithToken. However, I can then check for the token:
let token = TokenManager.fetchToken(Configuration.getDefaultAccessTokenIdentifier(), accessGroup: "com.MYCOMPANY.MYAPP.share")
print(token)
The token is "nil". I don't think the SDK is saving the token into the access group keychain.
When I use the default keychain (not the keychainAccessGroup), the login in the app works fine and I can get the login token back and make restricted calls to the API. However, that doesn't help the widget, which needs the token from the access group keychain.
Solved!! After many hours of debugging, and searching. What was not clear in ANY documentation is the keychainAccessGroup MUST include the AppIndentifierPrefix. That's the 10 character identifier associated with the App ID. So, instead of using "com.MYCOMPANY.MYAPP.share", it's "APPID.com.MYCOMPANY.MYAPP.share" for the keychainAccessGroup.

how to authorise OAuth2 in tvOS

app going to unknown state and doesn't do anything i'm having this code in didFinishLaunchingWithOptions for P2Auth2 and can't authorise
Authenticator.sharedInstance.oauth2 = OAuth2
Authenticator.sharedInstance.reauthorizeSilently(callback: { (wasFailure, error) -> Void in
if (!wasFailure) {
print("Re-Auth Successfull")
} else {
print("Re-Auth failed")
}
})
return true
As tvOS does not support web views, it seems unlikely that you will be able to directly log in from AppleTV. Most AppleTV solutions that succeed use a second device to acquire the OAuth login token. If you can authenticate directly without using OAuth2, I recommend that you do so.

Azure App Service Facebook

I've migrated from Azure Mobile Service to an App Service but I'm having difficulty working out how best to implement extended Facebook auth.
In my old implementation I inherited from FacebookLoginProvider and fetched the token from the claims. I then added the CustomFacebookLoginProvider to my login providers. I then use the token to fetch more information about the user (their date of birth, friends and gender). With this information I created a user object and saved it to my DB.
Does anyone have any suggestions on how best to recreate this in App Service as I can't find any documentation.
As far as how to set up Facebook authentication, you can find documentation here (and it sounds like you've already figured out this much):
https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-how-to-configure-facebook-authentication/
Now that Facebook authentication is set up, you can refer to the following which shows how to obtain user information:
https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-dotnet-backend-how-to-use-server-sdk/#user-info
// Get the credentials for the logged-in user.
var credentials =
await this.User
.GetAppServiceIdentityAsync<FacebookCredentials>(this.Request);
if (credentials.Provider == "Facebook")
{
// Create a query string with the Facebook access token.
var fbRequestUrl = "https://graph.facebook.com/me?access_token="
+ credentials.AccessToken;
// Create an HttpClient request.
using (var client = new System.Net.Http.HttpClient())
{
// Request the current user info from Facebook.
using (var resp = await client.GetAsync(fbRequestUrl))
{
resp.EnsureSuccessStatusCode();
// Do something here with the Facebook user information.
var fbInfo = await resp.Content.ReadAsStringAsync();
}
}
}
Note that you must add a using statement for System.Security.Principal to make the GetAppServiceIdentityAsync extension method work.
For more information on which Facebook user properties you can query, see the Facebook documentation here: https://developers.facebook.com/docs/graph-api/reference/user. Note that you may need to specify which user properties you want as an additional fields query string parameter on your call to the Facebook graph.
The only change I had to make when switching from Mobile Service to Mobile App was to change the end of the callback URL in the developer portal to use /.auth/login/facebook/callback instead of /signin-facebook and it worked exactly the same way as before.
Note that this is for a Windows app with a .NET backend; you didn't specify what you're using so your mileage may vary.
I've been using the following approach to obtain the Facebook Access Token in the iOS app.
App Services includes the Facebook Access Token in the request header, refer to https://azure.microsoft.com/en-in/documentation/articles/app-service-api-authentication/.
To get to the access token, create a Custom API in the Azure Portal, e.g. facebookUserInfo, with the following code:
module.exports = {
"get": function (request, response, next) {
response.send(200, { facebookAccessToken: request.headers['x-ms-token-facebook-access-token'] });
}};
In the iOS app, use the following code to query the custom API:
let client = self.table!.client
if client.currentUser != nil {
client.invokeAPI("facebookUserInfo", body: nil, HTTPMethod: "GET", parameters: nil, headers: nil, completion: { (result, response, error) -> Void in
if let resultDict = result {
if let facebookAccessToken = resultDict["facebookAccessToken"]! {
print(facebookAccessToken)
}
}
}
}
By Using the Easy Auth feature of Azure App Services, I dont need to worry about authentication.
I have a blogpost on this. I have explained on how we can use the FB GraphApi's to query FB data. Here is the link: https://blogs.msdn.microsoft.com/kaushal/2017/06/08/using-easy-auth-to-query-facebook-information-via-graph-api/
I have the sample code deployed on Github. Here is the link: https://github.com/kaushalp/Facebook-GraphApi-with-EasyAuth