Skip to content
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

feat: Expose Granted Scopes while fetching credentials #230

Merged
merged 6 commits into from
Sep 1, 2023

Conversation

bajajneha27
Copy link
Contributor

@bajajneha27 bajajneha27 commented Aug 11, 2023

When user credentials are fetched and refreshed, the OAuth server returns granted scopes. This change exposes those scopes in the credentials object

lib/signet/oauth_2/client.rb Show resolved Hide resolved
if status == 200
parsed_response = ::Signet::OAuth2.parse_credentials body, content_type
parsed_response["granted_scopes"] = parsed_response.delete("scope") if parsed_response
parsed_response

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this be a return statement?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The return keyword is not necessary, and is generally idiomatically omitted, since the value of the last expression in a method (which in this case is whatever clause in the if-elsif-else is selected), is implicitly the return value.

That said, this construct would be better turned around, because currently the return value is buried in the middle of the method and thus isn't obvious. (It also invites a subtle bug where someone might inadvertently add another statement after this if-elsif-else clause, thus causing something different to be returned from the method.) It would be better for the else clause to be elsif status != 200, and then put this parsed_response stuff at the very end of the method, so that the return value is positioned in the obvious place at the end.


if status == 200
parsed_response = ::Signet::OAuth2.parse_credentials body, content_type
parsed_response["granted_scopes"] = parsed_response.delete("scope") if parsed_response

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain this line to me please? I am not familiar with Ruby nor this library.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already have a field called scope which represents the requested scope. The update_token method updates the field scope if the options hash passed to the method contains a key scope. I need to make sure that we're not mixing the requested scope and granted scopes. So, I create a separate key called granted_scopes ( and delete the scope key so that it doesn't get updated for requested scope ) and pass it to update_token method.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIUC, "scope" field was already existing, if options had it, then the field is set. Now, that functionality is being removed?

I am trying to understand why both "Scopes" and "granted_scopes" cannot co-exist.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIUC, "scope" field was already existing, if options had it, then the field is set. Now, that functionality is being removed?

The scope field here represents granted_scopes while the already existing scope field represents requested scopes. We need to differentiate the two and hence this deletion .

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me know if it isn't clear. We can discuss it offline

@bajajneha27 bajajneha27 marked this pull request as ready for review August 11, 2023 17:04
@bajajneha27 bajajneha27 requested a review from a team as a code owner August 11, 2023 17:05
@bajajneha27
Copy link
Contributor Author

@sai-sunder-s Gentle reminder :)

# expressed as either an Array of String objects or as a
# space-delimited String.
def granted_scopes= new_granted_scopes
@granted_scopes = new_granted_scopes&.split
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If an Array is passed in for new_granted_scopes (see your docs above), it won't respond to the message split.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. I have updated the docs to reflect the expected behavior here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd suggest allowing Array to be passed. Otherwise, granted_scopes= takes a String but granted_scopes returns an Array, which would be confusing and invite buggy usage.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't want this method to accept Array since we get space delimited String in response and this method should ideally not be used to update granted_scopes manually.
But for the sake of not introducing bugs, I'll make the change.

##
# Sets the scopes returned by authorization server for this client.
#
# @param [Array] new_granted_scopes
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you want to support both Array and String (see your docs below), you should include both types here.

Also, do we need to support setting it back to nil?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for pointing this out. This was a miss from my end.
The auth server returns a space delimited string, so I thought of supporting only String for now.
And yes, we can set it back to nil.

spec/signet/oauth_2/client_spec.rb Show resolved Hide resolved
@@ -167,6 +170,8 @@ def initialize options = {}
# - <code>:extension_parameters</code> -
# When using an extension grant type, this is the set of parameters used
# by that extension.
# - <code>:granted_scopes</code> -
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use backticks instead of html tags?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@bajajneha27
Copy link
Contributor Author

@dazuma I addressed all the comments.

@@ -32,52 +32,54 @@ class Client
#
# @param [Hash] options
# The configuration parameters for the client.
# - <code>:authorization_uri</code> -
# - `authorization_uri` -
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd keep the colons to emphasize that the keys are symbols.

# expressed as either an Array of String objects or as a
# space-delimited String.
def granted_scopes= new_granted_scopes
@granted_scopes = new_granted_scopes&.split
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd suggest allowing Array to be passed. Otherwise, granted_scopes= takes a String but granted_scopes returns an Array, which would be confusing and invite buggy usage.

##
# Returns the scopes granted by the authorization server.
#
# @return [Array] The scope of access returned by the authorization server.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like this can return nil as well as Array, if the granted scopes were never set.

@bajajneha27 bajajneha27 merged commit 48a6b78 into googleapis:main Sep 1, 2023
10 checks passed
# A shared symmetric secret issued by the authorization server,
# which is used to authenticate the client.
# - <code>:scope</code> -
# - `:scope` -

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is still listed in the comment but no longer exists; it's deleted below

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants