Is there a way to detect revoked permissions through Google APIs? - google-account

We're trying to find a way to detect revoked permissions through Google APIs without continuously polling the provider to get status updates. Does Google have any sort of notification system for this (a webhook, etc)?
The most recent post I found regarding this was over 2 years ago.

Look here and search for Check For Permissions
Android Permissions
// Here, thisActivity is the current activity
if (ContextCompat.checkSelfPermission(thisActivity,
Manifest.permission.READ_CONTACTS)
!= PackageManager.PERMISSION_GRANTED) {
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
Manifest.permission.READ_CONTACTS)) {
// Show an expanation to the user *asynchronously* -- don't block
// this thread waiting for the user's response! After the user
// sees the explanation, try again to request the permission.
} else {
// No explanation needed, we can request the permission.
ActivityCompat.requestPermissions(thisActivity,
new String[]{Manifest.permission.READ_CONTACTS},
MY_PERMISSIONS_REQUEST_READ_CONTACTS);
// MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
// app-defined int constant. The callback method gets the
// result of the request.
}
}

Related

How to detect that the current request is an authentication callback?

I have a single-page JavaScript application and I'm using the Auth0 service for signup/login.
I have integrated the Lock widget and I'm saving a string to localStorage after a user is authenticated, like so:
lock.on("authenticated", function(authResult)
{
localStorage.setItem('login', authResult.idToken);
}
The problem is that when Auth0 redirects them back to my application after logging in, the authenticated event is fired only after page loaded, but by that time, I've already done the check to see if the localStorage string is set (which it is not); therefore, the user just keeps getting asked to login again:
if(localStorage.getItem('login') == undefined)
{
lock.show(function(err, profile, token)
{
// ...
}
}
I tried to see if there was anything special passed in to the page after a callback - but the referrer isn't always there.
If I don't automatically prompt the user to login, but instead show a login button - the authenticated event never fires for some reason.
How do I get around this?
Based on the information provided you seem to be using Lock in redirect mode and if that's the case you can use the hash_parsed event as a way to know if Lock found a response that it will process.
Every time a new Auth0Lock object is initialized in redirect mode (the default), it will attempt to parse the hash part of the URL, looking for the result of a login attempt. After that, this event will be emitted with null if it couldn't find anything in the hash. It will be emitted with the same argument as the authenticated event after a successful login or with the same argument as authorization_error if something went wrong.
Leveraging this event you could do the following:
Subscribe to the hash_parsed event:
If hash_parsed is emitted with null and localStorage has no indication the user already logged in then redirect to login.
If hash_parsed is emitted with a non-null value that either the authenticated or authorization_error will be emitted and you can react accordingly.
Some sample code:
lock.on("hash_parsed", function (response) {
if (!response && !localStorage.getItem('login')) {
// Redirect to the login screen
} else {
// Either the user is already logged in or an authentication
// response will be processed by Lock so don't trigger
// an automatic redirect to login screen
}
});

How to force Google OAuth popup in Firebase when user already authenticated previously?

Whenever a user has previously authenticated with Google, it automatically defaults to logging them in with THAT account on subsequent attempts. I want to eliminate this and force the popup/redirect so that a user with multiple google accounts can choose which one to use. How?
Background:
The automatic logging in feature is proving problematic for me as I have a whitelisted set of e-mails for users allowed to use my app. If a Google user chooses the wrong account when first logging in, they can't go back and choose the one associated to their whitelisted e-mail.
Just as #nvnagr said, you can do this with the following code:
var provider = new firebase.auth.GoogleAuthProvider();
provider.setCustomParameters({
'prompt': 'select_account'
});
But I think you need to update the firebase version to 3.6.0 something.
Google supports a parameter in authentication url to deal with this issue.
If you add prompt=select_account in your request to Google authentication, it'll force the user to do an account selection. See the details and other values of prompt.
https://developers.google.com/identity/protocols/OpenIDConnect#authenticationuriparameters
I'm not sure if there is an easy way to add this parameter through firebase api.
When you're calling the oAuth function, you can pass a third options parameter to make the authentication last for the session only. This should solve your problem. Docs
var ref = new Firebase("https://<YOUR-FIREBASE-APP>.firebaseio.com");
ref.authWithOAuthPopup("google", function(error, authData) {
if (error) {
console.log("Login Failed!", error);
} else {
console.log("Authenticated successfully with payload:", authData);
}
}, {
remember: 'sessionOnly'
});

Able to POST direct messages using Twitter's REST API, but trying to GET returns a 401 error

I am trying to get direct messages working in my app. I'm able to POST DMs just fine, but when I try to GET them from the endpoint https://api.twitter.com/1.1/direct_messages.json it returns a 401 - Unauthorized. I don't really understand how I can be authorized to send DMs but not get ones sent to me.
Here's how I'm authenticating initially:
if Twitter.sharedInstance().sessionStore.session() == nil {
Twitter.sharedInstance().logInWithCompletion { session, error in
if (session != nil) {
// successfully logged in, call loading functions
} else {
print("error: \(error!.localizedDescription)")
}
}
} else {
// already logged in, call loading functions
}
Every time I make a request using the REST API, it begins with
if let userID = Twitter.sharedInstance().sessionStore.session()?.userID {
let client = TWTRAPIClient(userID: userID)
The client is initialised the same way in both the POST and GET requests for DMs, yet the GET request fails.
As far as permissions go, I've checked that it has read/write/DM access according to Twitter, and successful requests return "x-access-level" = "read-write-directmessages";, so I think it's set properly.
I was concerned at one point that I might not be authenticating properly, since Twitter's documentation goes through the 3 step process for O-Auth and all I'm doing is telling the Twitter singleton to just log in... but I rationalised that away by assuming that those steps are all carried out in the logInWithCompletion function. And besides, if I wasn't authenticated properly I surely wouldn't be able to send DMs, right?
Any ideas on how I can fix this? I'm quite new so it may be something nice and simple! I've looked through some other questions, but they all seem to code the requests in full rather than using built-in methods like these - or have I got it all wrong?
Yeah, it was a stupid problem - I left the parameters blank since they are all marked as 'optional' - as in, a dictionary of ["" : ""]. I just set the paramaters in the request to nil, and now it works.

Authenticating with ReactiveCocoa

I'm building an app on top of ReactiveCocoa and Octokit.objC (github library). As part of my effort I'm using Octokits ReactiveCocoa signals to access resources that require authentication. A previous question 'Retrying an asynchronous operation using ReactiveCocoa' does a nice job covering the case where the user wants to 'retry an asynchronous operation' once. I'm trying to figure out how to handle the case where you might want to retry several times.
In my specific case if authentication fails I want to go ask the user for their credentials. I'll either ask the user for their credentials a few times (2 or 3) and then halt if they fail or I'll just keep asking them for their credentials until they succeed.
Any help would be appreciated. Thanks - AYAL
There is an operator called -retry: which accepts a count parameter. If you apply this operator to a signal, and that signal returns an error, it will re-subscribe to the signal (up to the specified number of times) when the error is received. So what you need is a signal that, when subscribed to, prompts the user for credentials.
#weakify(self);
RACSignal *requestCredentials = [RACSignal defer:^{
#strongify(self);
// (Prompt the user for credentials.)
if (successful)
{
self.cachedCredentials = credentials;
return [self authenticate:credentials];
}
else
{
return [RACSignal error:[[MyError alloc] init]];
}
}];
// We try to authenticate using the cached credentials (the
// `-authenticate:` method returns a signal that attempts
// authentication when it is subscribed to). If the initial
// attempt to authenticate fails, we try 3 times to get the
// user to enter the correct credentials.
return [[self authenticate:self.cachedCredentials]
catchTo:[requestCredentials retry:3]];

iOS OneDrive (skydrive) app displays permissions dialog every time it runs

I'm developing an iOS app that gives users access to their OneDrive/SkyDrive and I've run into a very annoying issue:
The very first time a user links the app to their OneDrive, everything goes as expected:
They have to enter a user id and password
Then they have to agree to let the app access their info
Then they get to browse their OneDrive
That's all good.
But, if the app closes, and you try to access the OneDrive again, rather than skipping straight to #3, and being able to access the OneDrive, they are stopped at step #2 (step 1 is skipped, as expected) and they have to agree again to let the app access their info.
The code is taken directly from the iOS examples in the online documentation (with some slight modification based on samples found here on Stack Overflow), but, here it is for inspection:
- (void) onedriveInitWithDelegate:(id)theDelegate {
self.onedriveClient = [[LiveConnectClient alloc] initWithClientId:MY_CLIENT_ID
delegate:theDelegate
userState:#"initialize"];
}
And then, theDelegate implements this:
- (void)authCompleted:(LiveConnectSessionStatus) status
session:(LiveConnectSession *) session
userState:(id) userState {
NSLog(#"Status: %u", status);
if ([userState isEqual:#"initialize"]) {
NSLog( #"authCompleted - Initialized.");
if (session == nil) {
[self.onedriveClient login:self
scopes:[NSArray arrayWithObjects:#"wl.basic", #"wl.signin", #"wl.skydrive_update", nil]
delegate:self
userState:#"signin"];
}
}
if ([userState isEqual:#"signin"]) {
if (session != nil) {
NSLog( #"authCompleted - Signed in.");
}
}
}
I thought that perhaps the status value might give a clue and that maybe I could avoid the login call, but it's always zero/undefined when I get to authCompleted after calling initWithClientId. (And session is always nil.)
Is there a scope I'm missing? Is there a different call to make rather than a straight-up login call? Or is it more complicated than that? I've seen reference to "refresh tokens" related to OAuth2 login, but I've not been able to find any concrete examples of how they might be used in this situation.
Any help and/or insights greatly appreciated.
Diz
Well, it turns out that the answer is pretty simple here. I just needed to add the "wl.offline_access" scope to my list of scopes during the initial login operation. The docs didn't really imply this type of behavior for this scope, but, that did the trick for me.
With this new scope added, subsequent invocations of the app no longer bring up the "agree to give the app these permissions" dialog, and I can go straight to browsing the OneDrive.
(Credit where it's due: Stephane Cavin over at the microsoft forums gave me the tip I needed to work this out. Gory details are here:
http://social.msdn.microsoft.com/Forums/en-US/8c5c7a99-7e49-401d-8616-d568eea3cef1/ios-onedrive-skydrive-app-displays-permissions-dialog-every-time-it-runs?forum=onedriveapi )
Diz

Resources