New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Incremental auth support #624
Conversation
Thanks for your pull request. It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). 📝 Please visit https://cla.developers.google.com/ to sign. Once you've signed, please reply here (e.g.
|
I have signed the CLA. |
We found a Contributor License Agreement for you (the sender of this pull request), but were unable to find agreements for the commit author(s). If you authored these, maybe you used a different email address in the git commits than was used to sign the CLA (login here to double check)? If these were authored by someone else, then they will need to sign a CLA as well, and confirm that they're okay with these being contributed to Google. |
I have again signed the CLA with my other account I didn't realize I was using, apologies. |
CLAs look good, thanks! |
Wouldn't it be better to add it here then to just overload the method? |
Thank you very much for this pull request! It's exciting to see contribution like you trying to make this library better 👍
userCredentials = await GoogleWebAuthorizationBroker.AuthorizeAsync("scope 1", ... , "include_granted_scopes=true"). Then you need to actually add "scope 2", since your are trying call a service that requires it. userCredentials = await GoogleWebAuthorizationBroker.AuthorizeAsync("scope 2", ... , "include_granted_scopes=true") and since the user already added scope1, the output credential will result in token for both "scope 1" and "scope 2"?
Thanks again! |
Linda: I'm not entirely understanding your question. I did add it to GoogleAuthorizationCodeRequestUrl.cs, but in addition I overloaded the methods in order to expose this setting easily to users of the library such as myself. Since the majority of the library tends to be abstracted away from those such as myself, after reviewing the code I determined the best way to grant a user access to control this setting was to overload the methods, starting with If I had just added it to the GoogleAuthorizationCodeRequestUrl.cs, I didn't see a good way to allow a general user to be able to append scopes, which I felt is a fairly necessary thing to be able to access and control (as opposed to ApprovalPrompt for instance, which may not be accessed or changed as often). I could, of course, have missed something in the code when I was walking through with the debugger. I tried to identify the best entry point for this code without breaking backward compatibility, so if I missed something I have no qualms against going a different direction! Eyal, if I'm understanding your question correctly - the initial request (again, to my understanding of the api and the documentation) - wouldn't matter what you passed for the parameter since there is no previous authorization to work against. In my testing, setting it to true for the first authorization didn't error out, so it seems to just ignore it in that case (since there is nothing to append scopes to). In the subsequent authorizations when you don't want the default behavior of replacing scopes, you do have to explicitly set the parameter to true. Setting it to false or leaving it blank (null) will induce the default behavior of replacing scopes, rather than appending. and since the user already added scope1, the output credential will result in token for both "scope 1" and "scope 2"? Based on the description here, it will output a single token but instead of this token just representing the scopes you supplied with this auth request, it will append those scopes to the scopes you had assigned to this project from prior requests. I think that Incremental Authorization should work for Installed App as well: Unfortunately, I and other users have had no such luck. At this time I don't have experience with non-installed apps to test this with but I wanted to get the ball rolling. I'd be happy to take this offline for another discussion if you feel it's not appropriate here, but until I can figure out how to do something other than an installed app without access to a webserver or something my hands are a bit tied (and no time, friggin babies man). I'll be on the road for the next few days, so I apologize if I misread your questions in my haste or don't get back to any questions or comments soon enough! Thanks for your consideration. |
Thanks for all the content you added. I'm still not convinced that your change will actually do something, and here is the reason: Whenever you call AuthorizeAsync, you actually call this AuthorizeAsync of the InstalledApp class: By taking a look in this implementation, I see that whenever we have a token, we just use it. So I think that in your flow although we will set include_granted_scopes=true, nothing will happen. We will load the token form the data store, and because with the current code we don't compare scopes (we actually don't have a way to do it right now), we will just use it. We need to add some path in the code to check if include_granted_scopes is set to true, and then don't use the current token. We definitely need to test it, and make sure it works. I'm currently swamped with other things on my plate (like everyone else, right?), but I'll try to get into it later on this week. Thanks again, hope that my comment is clear and correct me if I'm wrong regarding anything I said... |
Thinking out loud. We need a way to know what scopes the initial datastore was created with. Then we can detect if the new scopes are being passed are the same as the old dataStore or not. If they aren't then we can request access for these new scopes. This would require a change to datastore to save the scopes also. We could just set it always to true but i am not sure this is a good idea what if you wanted to remove them there will be no way to remove them. Really i think it needs to be the client library that figures out what needs to be set developers shouldn't have to do this. However we could add an optionValues to AuthorizeAsync support this and other items like the ones below. Here are a few other things we might want to consider merging in with this approval_prompt #524 |
I don't agree that we need to change the datastore structure, since in a IMO, we just need to change the code I mentioned that if the incremental Eyal On Mon, Nov 9, 2015, 6:49 AM Linda Lawton notifications@github.com wrote: Thinking out loud. We need a way to know what scopes the initial datastore was created with. We could add an optionValues to AuthorizeAsync support other items like the Here are a few other things we might want to consider merging in with this approval_prompt #524 — |
Understood, thanks for clearing up what you meant. I had previously played with this method until realizing I could simplify things, but I had neglected to realize what you mention, thanks for catching that. I agree that there shouldn't be a need to keep track of what scopes we're using - we just in some way need to make sure the token coming back should or shouldn't replace what is there. I think if we update Otherwise, if we wanted to explicitly check/use these parameters via my current implementation (via the initializer -> flow path) we'd have to at least cast the Flow to access these parameters that don't exist on the interface, which is ugly. I get back later this week, I can throw something together and see if I can get something working. I'll also look in to the other parameters Linda mentioned - if most of them don't need to be considered in |
Thanks. (Just something to consider) Eyal |
I wonder if adding request_visible_actions could be added to this as well. Posting moments to g+ still doesn't work without that. |
Sorry for the delay.
Why add it to AuthorizationCodeFlow.Initializer instead of the GoogleAuthorizationCodeFlow.Initializer that inherits it? With this and all the other parameters suggested here, if they're going to be specific to Google as opposed to generic OAuth 2.0 (for instance, Either way, that's the direction I'm heading - adding the parameters to the initializer and making the As to what I'm thinking beyond that - since we need the A lot of word salad, I know. I'm working on the updates to the code now, just trying to properly add in the parameters suggested by Linda before updating the pull request. |
Just a thought in a different direction and please let me know if you'd rather not have the project act this way - but what if instead of explicitly adding all these query parameters, I were to instead add an array of KeyValuePair objects that could represent any other query parameters the user specified? The user would specify that array in much the same way as we discussed - via the auth initializer - but it would give them the freedom to add in any other parameters (and as many as) they wanted. I've already targeted how to do it - roughly by adding a new type to the RequestParameterType enum (CustomQuery), updating the Assuming that most of the OpenID parameters mentioned above and other future parameters don't require an existing token to be replaced (as does the incremental auth), all it would need to do is show up in the URL, correct? The resulting code/token exchange would then proceed as normal. If so, I don't think that's in the scope of this pull request and I can open a separate one for that once I'm done with this. Please let me know your thoughts - otherwise, I'll look in to manually and explicitly adding the missing OpenID parameters as previously planned. |
Linda - I left out the other parameters for now pending your thoughts on my above comment. Eyal - I've updated the interface to allow for the Flow to indicate if/when the token should be forced to be retrieved and stored, it should alleviate the issue you described. I elected to update the Interface to keep things clean, and the method I added could have applications down the line. If you'd rather me not alter the interface I can work around it though it might not be as clean. |
I know that request_visible_actions is proably just a G+ thing at this time but iwth out the ablity to set it we moments.insert wont work. I have had to hack my own version of the library to get this to work. Wall of text on this My thoughts are you are awesome i have wanted to do this for months but could never figure out how to do it and make it look "nice" Keep up the good work. I will leave code review to Eyal :) |
@@ -113,17 +113,22 @@ public class GoogleWebAuthorizationBroker | |||
/// <param name="taskCancellationToken">Cancellation token to cancel an operation.</param> | |||
/// <param name="dataStore">The data store, if not specified a file data store will be used.</param> | |||
/// <returns>User credential.</returns> | |||
private static async Task<UserCredential> AuthorizeAsyncCore( | |||
public static async Task<UserCredential> AuthorizeAsyncCore( |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
I'm starting the review now... |
GoogleAuthorizationCodeFlow.Initializer initializer, IEnumerable<string> scopes, string user, | ||
CancellationToken taskCancellationToken, IDataStore dataStore = null) | ||
CancellationToken taskCancellationToken, IDataStore dataStore = null, | ||
bool? includeGrantedScopes = null) |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
@@ -88,7 +87,18 @@ public ICodeReceiver CodeReceiver | |||
taskCancellationToken).ConfigureAwait(false); | |||
} | |||
|
|||
return new UserCredential(flow, userId, token); | |||
return new UserCredential(Flow, userId, token); |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
… minor code tweaks.
Thanks again, you're too kind! My programming origins are isolated and humble indeed and I know I have a lot to pick up on, so I really do appreciate how cool and patient you've been with the whole process. Unfortunately I've only ever dealt with the installed app scenarios. I'll look around for some sample code I might be able to quickly run without having to do a ton of binding redirects and modifications to in order to get it running. I'll check out the quick-start app mentioned here later when I can keep my eyes open a bit longer =) |
Hi thanks again :) You're pretty awesome as well. |
Thanks so much! That means there might be a light at the end of the tunnel for my users and me! |
There is always light! I'll keep you updated, |
@squid808 and i went though this a little on stack all the documentation we found appears to refer only to web and mobile apps. It appear it wasn't implemented for installed apps. I can put together a quick test without the client library to find out if it works or not. Either way look forward to hearing what the Oauth gurus say. |
Someone also mentioned to me that Incremental Auth doesn't work for installed app.
Then we can commit 👍 I'll try to spend sometime with it later on this week. @squid808 if you have time, you should test it too. |
OK. I tested your code and with a small fix it works for Web applications
It might be changed in the future but for now, it isn't supported. An alternative is to delete your code form the Installed Apps flow, but I think that we should leave it as it is, because maybe in the near future this support will be added. So we need to add more documentation in
|
… Auth isn't supported for installed apps.
Sorry - I spent some time trying to learn how to do web dev enough to refactor the task api sample to work, but I hadn't gotten far enough in the limited time I had. You beat me to it =). I did however see that we needed to add it to the web auth, so I had done that. However, I duplicated the ShouldRequestAuthorizationCode for now to get things working similarly. I assume it should go in some utility class, but I wasn't sure if you had a particular class in mind. That said, I added a sentence description for each class you mentioned (I assumed your second link was a typo and you actually meant the AuthorizationCodeInstalledApp.cs file?), let me know if it's good or not. I'll check in periodically tomorrow to try and get this done. |
// If the stored token is null or it doesn't have a refresh token and the access token is expired we need | ||
// to retrieve a new authorization code. | ||
if (token == null || (token.RefreshToken == null && token.IsExpired(flow.Clock))) | ||
//Check if a new authorization code is needed. |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Thanks for the quick response. Just fix the small comments issues I raised, and we are ready to submit it. |
Ok, should be good per your comments. I noticed a spacing issue just after I hit push, and thus the second. Sorry for all the extra work, I feel like you've written more here in the comments than you would have just adding the code yourself. I'll check back throughout today in case you spot something else I missed. Thanks! |
@@ -19,6 +19,7 @@ | |||
using System.Threading.Tasks; | |||
|
|||
using Google.Apis.Auth.OAuth2.Flows; | |||
using Google.Apis.Auth.OAuth2.Responses; |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
I didn't. That's the process of the review. I added two tiny comments, address them and we are ready to push 👍 That's great because it's going to be part of the coming release! Exciting :) |
Done and done, thanks! |
I just thought to mention here the following SO thread: Thanks! |
I actually have it mostly done and seemingly working - I've been keeping it in a separate branch until we merged this one. I can create a separate issue if you'd like, or just submit the pull request once it's ready. I figured this one was a little more simple to cut my teeth on for the unit tests, so I was attempting that - and I'm also trying to figure out how to do the web application to test it in. Now that I'm a little more familiar with the process, I can try to get as much of that done first as I can. I also have to create the issue to request the unit tests for Either way, your call - I can create an issue for both if you'd prefer. |
Thanks! |
This adds support of the library to authenticate with the
include_granted_scopes
parameter which does not currently exist.Usage is intended to be exposed to a user of the library who is already using
GoogleWebAuthorizationBroker.AuthorizeAsync()
by adding a single new parameter -includeGrantedScopes
- which is a nullable bool and set to null by default. For example:If the user omits this optional parameter the null is trickled down and is ignored when building the authorization request URL (thereby defaulting to false in the request). When explicitly included, the query parameter is included in the URL with the value supplied, even if false.
I have tested it up to the point of verifying that it creates the url with the appropriate query parameters as expected, and ensured that the URL resolves and supplies an appropriate authentication page in the browser. I have not been able to test the resulting tokens however due to my applications being all installed applications at this time, which do not work with Incremental Authorization to my knowledge.
A proper test could likely be set up to ensure that the resulting url contains the parameter when expected, however I haven't fully wrapped my head around the mocking setup used in the project's tests. If someone would be willing to guide me through it I'd be more than happy to work on that as well, though my experience with tests is somewhat limited.
This also fixes two minor typos I came across for which I saw no need for a separate pull request. It's also my first pull request, so please let me know if I have done something incorrectly during the process.