Uber API OAuth on watchOS 6.2 using ASWebAuthenticationSession - uber-api

I'm trying to authenticate with Uber's API using watchOS 6.2's new OAuth capability ASWebAuthenticationSession:
ASWebAuthenticationSession(url: uberUrl, callbackURLScheme: scheme) { (URL?, Error?) -> in {
print(callbackUrl, error)
if let url = callbackUrl {
let components = NSURLComponents(string: (url.absoluteString))
if let t = components?.queryItems?.filter({$0.name == "code"}).first?.value {
self.token = t
}
}
}
When I run it, an adorable little web browser comes up on the Watch and prompts for a "E-mail or Mobile Number", after entering my e-mail, clicking on "Next" pops up a text entry window which then suddenly disappears, leaving me back at e-mail entry. The subsequent clicks on "Next" brings up a text entry window which only allows me to edit the e-mail address. Password is never an option. I never got the closure to complete, not even with en error.
If I scroll down to "Login with Google", then Google's login page loads, and lets me enter e-mail and password, and the completion block executes (I get a nil token presumably because my Uber account is not a Google one).
I suspect an issue with Uber's login webpage, but can't verify that other than observing that Google's seems to work. Also, I can find no documentation on the callbackURLScheme parameter with respect to watchOS. I create a scheme in the plist as one might with an iOS app, but can't confirm this is the correct procedure. Nonetheless, it doesn't change the fact that the password field will not come up on Uber's oath login page.
Searching StackOverflow for watchOS and ASWebAuthenticationSession produces no results at this point.
Is anyone else trying to do this right now? Has anyone had success? Am I missing something important, or is this simply an error on Uber's part?

Related

Actions on Google implicit account linking works in simulator/browser, but not on device (via Google Home app)

I've implemented the implicit flow for Actions on Google account linking, and am using Dialogflow (previously API.AI) to define intents.
The full flow works in the device simulator (from AOG). The first intent gets a "It looks like your account isn't linked yet..." response, and the debug pane includes a URL to initiate linking:
https://assistant.google.com/services/auth/handoffs/auth/start?account_name=[account]#gmail.com&provider=[project_id]_dev&scopes=email&return_url=https://www.google.com/
If I follow this URI in a cache-less window:
I'm redirected to my app's authentication page
I choose to sign in with my Google account (same as [account] above)
I'm redirected to google.com with a success message in the URI bar
The simulator now accepts actions via my app and responds correctly
However, if I follow the same flow using a physical Google Home & the gH app for Android.
Device tells me account not yet linked
Open Google home and follow 'Link to [my app]' link
Browser opens to authentication page
Sign in as user
Redirected to a white page with a single link "Return to app", which has an href: about:invalid#zClosurez
Linking was unsuccessful, so additional attempts to run intents on the Google Home get the same "Account not yet linked" response.
I've inspected the intermediate access_token and state variables at length, and they all match and look to be correctly formatted:
Authentication URL (app sign in page): https://flowdash.co/auth/google?response_type=token&client_id=[client_id]&redirect_uri=https://oauth-redirect.googleusercontent.com/r/[project_id]&scope=email&state=[state]
After authenticating, redirected to (this is the white screen with 'return to app' broken link): https://oauth-redirect.googleusercontent.com/r/genzai-app#access_token=[token]&token_type=bearer&state=[state]
So, it seems there's something non-parallel about the way the simulator and physical devices work in terms of implicit flow account linking.
I've been struggling with this, and with the AOG support team for a very long time to no avail. Anyone else see a similar issue?
Updated with response redirect code:
Login handled by react-google-login component with profile & email scopes. On success we call:
finish_auth(id_token) {
let provider = {
uri: '/api/auth/google_auth',
params: ['client_id', 'redirect_uri', 'state', 'response_type'],
name: "Google Assistant"
}
if (provider) {
let data = {};
provider.params.forEach((p) => {
data[p] = this.props.location.query[p];
});
if (id_token) data.id_token = id_token;
api.post(provider.uri, data, (res) => {
if (res.redirect) window.location = res.redirect;
else if (res.error) toastr.error(res.error);
});
} else {
toastr.error("Provider not found");
}
}
provider.uri hits this API endpoint:
def google_auth(self):
client_id = self.request.get('client_id')
redirect_uri = self.request.get('redirect_uri')
state = self.request.get('state')
id_token = self.request.get('id_token')
redir_url = user = None
if client_id == DF_CLIENT_ID:
# Part of Google Home / API.AI auth flow
if redirect_uri == "https://oauth-redirect.googleusercontent.com/r/%s" % secrets.GOOGLE_PROJECT_ID:
if not user:
ok, _email, name = self.validate_google_id_token(id_token)
if ok:
user = User.GetByEmail(_email, create_if_missing=True, name=name)
if user:
access_token = user.aes_access_token(client_id=DF_CLIENT_ID)
redir_url = 'https://oauth-redirect.googleusercontent.com/r/%s#' % secrets.GOOGLE_PROJECT_ID
redir_url += urllib.urlencode({
'access_token': access_token,
'token_type': 'bearer',
'state': state
})
self.success = True
else:
self.message = "Malformed"
else:
self.message = "Malformed"
self.set_response({'redirect': redir_url}, debug=True)
I am able to make it work after a long time. We have to enable the webhook first and we can see how to enable the webhook in the dialog flow fulfillment docs If we are going to use Google Assistant, then we have to enable the Google Assistant Integration in the integrations first. Then follow the steps mentioned below for the Account Linking in actions on google:-
Go to google cloud console -> APIsand Services -> Credentials -> OAuth 2.0 client IDs -> Web client -> Note the client ID, client secret from there -> Download JSON - from json note down the project id, auth_uri, token_uri -> Authorised Redirect URIs -> White list our app's URL -> in this URL fixed part is https://oauth-redirect.googleusercontent.com/r/ and append the project id in the URL -> Save the changes
Actions on Google -> Account linking setup 1. Grant type = Authorisation code 2. Client info 1. Fill up client id,client secrtet, auth_uri, token_uri 2. Enter the auth uri as https://www.googleapis.com/auth and token_uri as https://www.googleapis.com/token 3. Save and run 4. It will show an error while running on the google assistant, but dont worry 5. Come back to the account linking section in the assistant settings and enter auth_uri as https://accounts.google.com/o/oauth2/auth and token_uri as https://accounts.google.com/o/oauth2/token 6. Put the scopes as https://www.googleapis.com/auth/userinfo.profile and https://www.googleapis.com/auth/userinfo.email and weare good to go. 7. Save the changes.
In the hosting server(heroku)logs, we can see the access token value and through access token, we can get the details regarding the email address.
Append the access token to this link "https://www.googleapis.com/oauth2/v1/userinfo?access_token=" and we can get the required details in the resulting json page.
`accessToken = req.get("originalRequest").get("data").get("user").get("accessToken")
r = requests.get(link)
print("Email Id= " + r.json()["email"])
print("Name= " + r.json()["name"])`
Not sure which python middleware or modules you are using but
self.set_response({'redirect': redir_url}, debug=True)
seems to be setting parameters for a returning a response which isn't correct. Instead you should redirect your response to the redirect_url. For example importing the redirect module in Flask or Django like:
from flask import redirect or from django.shortcuts import redirect
then redirect like:
return redirect(redirect_url)
It appears Google has made a change that has partially solved this problem in that it is now possible to complete the implicit account linking flow outside of the simulator, in the way outlined in my question.
It seems the problem stemmed from an odd handling (on the AOG side) of the client-side redirect case used after sign in with the Google sign-in button.
From Jeff Craig in this thread:
The current workaround, where we provide the "Return to app" link
currently what we're able to provide. The issue is with the way that
redirecting to custom-scheme URIs is handled in Chrome, specifically,
with regard to the redirect happening in the context of a user action.
XHR will break that context, so what is happening is that you click
the Google Sign-In Button, which triggers an XHR to Google's servers,
and then you (most likely) do a client-side redirect back to the
redirect_url we supply, our handler executes, and isn't able to do a
JS redirect to the custom scheme URI of the app, because were outside
of the context of a direct user click.
This is more of a problem with the Implicit (response_type=token) flow
than with the authorization code (response_type=code) flow, and the
"Return to app" link is the best fallback case we currently have,
though we are always looking for better solutions here as well.
The current behavior shows the 'Return to app' link, but as of last week, this link's href is no longer about:invalid#zClosurez, but instead successfully completes the sign-in and linking process. It's an odd and confusing UX that I hope Google will improve in the future, but it was sufficient to get my app approved by the AOG team without any changes to my flow.

Unity Facebook SDK: FB.IsLoggedIn / FB.ShareLink issue

I'm trying to create my mobile app user to share my Facebook page and if they do, I give them an in-game item. I'm using the example code provided by Facebook here: https://developers.facebook.com/docs/unity/examples
The first issue is that FB.ShareLink doesn't comeback negative if the user cancels the sharing action. From what I've read, that's on purpose and it only works correctly if the user is logged in and my app is authorized. I tested it and that's true, if I use the login code to first login, it comes back as positive or negative correctly.
The second issue that I'm having though is that FB.IsLoggedIn never comes back negative and I'm not sure how to properly check this because even though it comes back as true, my app is note authorized and FB.ShareLink doesn't return negative when canceled. I start the Login issue and then I press the back arrow to cancel it but FB.IsLoggedIn still comes back as true.
How can I just check if the app is authorized? I'm guessing that's all I need to check before running the FB.ShareLink code.
Any ideas?
Thanks!
First, we try to login asking for the user's e-mail address.
public void LogIntoFacebook() {
List<string> perms = new List<string>() { "email" };
FB.LogInWithReadPermissions(perms, OnLogin);
}
Then you can check to see if you got the e-mail address permission using
AccessToken token = AccessToken.CurrentAccessToken;
if (token.Permissions.Contains("email")) { // do something }
If you do, then you move forward with the Facebook share.

Checking if person opening app is already an authenticated user FirebaseAuth swift

I have an app that uses Facebook authentication to login. When the onboarding screen is loading I check to see if the user is already authenticated and perform a segue to the home screen if they are using the code below:
override func viewDidLoad(animated: BOOL) {
super.viewDidLoad(animated)
if FIRAuth.auth()?.currentUser != nil {
performSegueWithIdentifier(loginSucessIdentifier, sender: self)
}
}
The thing is, if I create a test user on facebook and then sign into the simulator device with the test user login info, when I open the app it still says I am the user, not the test user and when I go to Main screen it still pulls up my info.
I checked all the examples and docs for firebase and can't find a place where they do this initial check.
Can anyone explain if I am doing the check wrong or if there is something with the facebook test user I am not doing properly.
Thanks
I finally figured out what the problem was. When a user clicks the signout button you also need to log out of facebook with FBSDKLoginKit. So when I signed back in it was still reading the credential from previous user facebook login.
let loginManager = FBSDKLoginManager()
loginManager.logOut()

Azure mobile facebook authentication with iPhone HTML5 in app (full screen) mode

I have an HTML5 application that uses Azure mobile services authentication to login (straight from the example code...provided below). It works fine in all desktop browsers and iPhone 5 in Safari. But from app / full screen mode, it does nothing (doesn't ask for permission to show a popup window like it does in safari and no popup windows shows up) and I can wait forever and nothing happens. If I invoke it a second time, it gives an error saying "Error: Unexpected failure"...perhaps because the 1st attempt is still running? Any help/insight is appreciated.
client.login ("facebook").done(function (results) {
alert("You are now logged in as: " + results.userId);
}, function (err) {
alert("Error: " + err);
});
edited update with more info and 2 potential ideas*
I did some more research and found a site that uses an approach that overcomes this problem and also solves two other side effects with the current Azure mobile approach to authentication. I think the Azure mobile team might be looking to do something similar because there are some hints of other authentication options in the code (although difficult to read and be sure because the minimized code is obsfucated). It might be just a matter of activating these in the code...
The "solution":
Go to http://m.bcwars.com/ and click on the Facebook login. You'll see it works perfectly in iPhone Safari in "app mode" becuase instead of doing a popup, it simply stays in the current browser window.
This approach solves two other problems with the current Azure mobile approach. First, the popup gets interpreted by most browsers as a potential ad and is either blocked automatically (desktop Chrome) ... and the user doesn't know why it's not working...or gives a warning which the user has to approve (iPhone Safari in "browser mode") which is a hassle. And if the user has a popup blocker, it gets more difficult and even more potential for the user not getting it to work properly. The bcwars.com method doesn't have this problem.
Second, in iPhone Safari, when the popup window auto closes, the original page doesn't get focus if there are other browser windows open in Safari. Instead, it's in the smaller/slide mode so they can choose which one to show. If this happens, the user has to go through one more sttep...click on the browser window to activate it and give it focus..again more of a pain and more potential for them to mess up and not do it correctly and need help. The m.bcwars.com doesn't have this problem.
Azure options:
Looking at the Azure mobile code it looks like may already have the solution. I can't read it easliy becuase it's minified/obsfucated, but it seems to have 4 options (including iFrame, etc.) for invoking the authentication, and only 1 (the "less ideal one" of a popup) is being used. An easy solution would be to set a property to allow one of the alternate authentications to work. But I can't read it well enough to figure it out. Another would be to hack the code (temporarily until a fix is put up by Microsoft).
Could I get some help there perhaps?
You can implement an authentication flow with Facebook that doesn't use a popup. The basic idea is to use the 'Web Flow' for doing the login, and once the window return from the login, use the access token to login the user in to Azure Mobile Services.
The Facebook documentation for doing this is here:
https://developers.facebook.com/docs/facebook-login/login-flow-for-web-no-jssdk/#step2
Some code samples to make it easier for you.
You would start by something like this:
(Remember to replace YOUR_APP_ID and YOUR_URL with something relevant to your site.
function logIn() {
window.location.replace('https://www.facebook.com/dialog/oauth?client_id=YOUR_APP_ID&redirect_uri=http%3A%2F%2FYOUR_URL&response_type=token')
}
This redirects the window to the Facebook page for the user to log in and authorize your app. When the user is done, Facebook will redirect the user back to YOUR_URL given above.
There you can handle the redirect and do the Mobile Services Login with something like this:
function handleLoginResponse() {
var frag = $.deparam.fragment();
if (frag.hasOwnProperty("access_token")) {
client.login("facebook", { access_token: frag.access_token }).then(function () {
// you're logged in
}, function (error) {
alert(error);
});
}
}
In here you parse the access token you get as a URL fragment and pass it as argument to the login call you make to Azure Mobile Services.
This code depends on the jquery BBQ plugin to handle the URL fragment easily.
Hope this solves your problem!

Graph Request Only Works With My Facebook Account

I have a web page which asks the user to log in and then proceeds to get JSon via Graph for a particular Facebook group. It builds the Uri dynamically by taking the access_token that is returned after login. It works fine when I do this, but if I try to log in with a different account, no data for the feed is returned.
One hint in this problem is when the facebook dialog screen appears, it only asks for my username/password. It doesn't ask go to the usual screen where Facebook asks for you to give permissions for "Basic Information" etc. It's just a username/password screen and then I go straight in.
This is the login code:
function login()
{
FB.login(function (response)
{
if (response.authResponse)
{
// connected
var authResponse = response.authResponse;
access_token = authResponse.accessToken;
refresh();
} else
{
// cancelled
}
});
}
One hint in this problem is when the facebook dialog screen appears,
it only asks for my username/password. It doesn't ask go to the usual
screen where Facebook asks for you to give permissions for "Basic
Information" etc. It's just a username/password screen and then I go
straight in.
This is because you've already authorized the app, so once you login it will take you straight to the app.
It works fine when I do this, but if I try to log in with a different
account, no data for the feed is returned.
Well the limited view of code you posted is fine, so something else is the problem. First debug step is to get the access token for that different account, and check the debugger to see if its tied to the appropriate user and scope.