Retrieving the Google API granted scopes for a client - google-api

We're using the hybrid auth flow, such that the client is requested for incremental grants via JS and the resulting code is passed up to our API server for processing.
What we need is one of:
Which scopes are available to a user, either via refresh token or access token
A way to include the current scopes in the $client->authenticate($code) response (so we can store them with the refresh token)
A way to determine which scope was just granted in the response from Google to $client->authenticate($code) (so we can append it to a stored list for that user)
We would like to present a list on the integrations page for the user to opt in to each feature (calendar, contacts, drive) and present a clear list of which features are enabled, in addition to prompting if they access a not-yet authorized feature. Even aside from that, I can't believe this isn't "a thing."

Was in the same position as you...If you hit: https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=
it will return a JSON response which has a "scope" parameter, which is a space-separated list of all granted scopes for the access token.

While I realize this is somewhat old now, for those finding this via Google from here on, it's probably worth noting that the access token bundle, as received back from, for example, PHP client library method $client->fetchAccessTokenWithAuthCode($_GET['code']), actually contains a list of the active scopes, with key "scope". You should be able to parse that without any need for further API calls.
Here's an example of what my access token bundle looks like:
{
"access_token": "xxxxxxxxxxx",
"expires_in": 3600,
"refresh_token": "xxxxxxxxxxxx...... ",
"scope": "https:\/\/www.googleapis.com\/auth\/userinfo.profile openid https:\/\/www.googleapis.com\/auth\/userinfo.email",
"token_type": "Bearer",
"id_token": "xxxxxxxxx...... ",
"created": 1576300135
}
Note the "scope" parameter in the above.
This doesn't appear to be documented anywhere.
Like you, some years later, I haven't yet found a client library method that supplies this functionality; and you're right, it seems rather basic (actually, a function to compare two lists of scopes would be ideal, including account for the expansion of 'profile' and 'email' scopes, hint hint Google folks!).
[apologies for switching to PHP for the example, but I suspect the access token bundle format is identical, so a similar approach should be possible]

Related

Google API access token meaning

Somebody has created a system which use Google API. It happens that I have been using this system for several months to upload files to G Drive and it worked very well.
However today I realized in the following string that there was an expiry date (not updated until today) which prevent from uploading files. My understanding is that a token is generated every time my code is requesting API access, but this shows the same access_token and refresh token with expiry date. I tried to read official doc without clear understanding. Can you explain simply what I should think about it and hint at how I should re generate the needed token please.
{"access_token": "xxx", "client_id": "yyy", "client_secret": "nnn", "refresh_token": "bbb", "token_expiry": "2021-02-24T05:33:24Z", "token_uri": "https://accounts.google.com/o/oauth2/token", "user_agent": null, "revoke_uri": "https://oauth2.googleapis.com/revoke", "id_token": null, "id_token_jwt": null, "token_response": {"access_token": "xxx", "expires_in": 3599, "scope": "https://www.googleapis.com/auth/drive", "token_type": "Bearer"}, "scopes": ["https://www.googleapis.com/auth/drive"], "token_info_uri": "https://oauth2.googleapis.com/tokeninfo", "invalid": true, "_class": "OAuth2Credentials", "_module": "oauth2client.client"}
How much i understood it is that as we need multiple parameters to access a Google API which include authentication etc. As there are multiple steps to validate an API call, if they succeed, we are provided with an access_token which now represents that all the processes (or authentication etc) was successfull and now the access_token is a proof for that. So after that, only the token will be checked (until its expiry date) and the process will repeat after the expiration.
The authorization sequence begins when your application redirects a browser to a Google URL; the URL includes query parameters that indicate the type of access being requested. Google handles the user authentication, session selection, and user consent. The result is an authorization code, which the application can exchange for an access token and a refresh token.
The application should store the refresh token for future use and use the access token to access a Google API. Once the access token expires, the application uses the refresh token to obtain a new one.
More details Here

Outlook IMAP scopes giving an AUTHENTICATE failure with new MS Graph API

I'm requesting the following scopes (URL encoded):
offline_access user.read https://outlook.office.com/IMAP.AccessAsUser.All https://outlook.office.com/SMTP.Send
The authorization process with OAuth 2.0 using the new Microsoft Graph API seems to work fine, but when using the access token to connect to IMAP over XOAuth2, I'm getting a NO AUTHENTICATE, which indicates the token is invalid.
It turns out this is not an issue with the user but rather with Microsoft's Graph API. Although it is not documented, you are currently not allowed to request a token with a scope that falls under two tenants, or it will choose one and fail silently.
In this case, User.Read falls under Microsoft Graph tenancy. Technically speaking, if your user is an organizational Outlook/Office365 user, they likely don't actually have Microsoft Graph installed and the correct scope would be https://outlook.office.com/User.Read. However the Outlook profile endpoint has been deprecated and would be unadvisable to use (you also have no way of knowing whether or not your user has MS Graph tenancy). It seems to resolve this, the user.read permission can be requested without specifying the Microsoft Graph URL.
This is essentially what you are doing above, but can be misleading as you are not actually requesting the general User.Read permission that can then be resolved to the Outlook tenant. What is actually happening is that User.Read permission is being mapped to some default tenant, and so your scopes actually contain multiple tenants (both the default tenant and Outlook).
Since this is not allowed, it fails silently and defaults to the default tenant. With most of their APIs this still works, but specifically with IMAP/SMTP you cannot request a larger scope/multi-tenant key or it will not validate over XOAuth2. You will note that the access tokens returned for IMAP/SMTP alone are always much smaller than the access tokens for other scopes.
To remedy this, you will need to request two access tokens. Firstly, you should use your authorization code to request a key within the following scope:
offline_access https://outlook.office.com/IMAP.AccessAsUser.All https://outlook.office.com/SMTP.Send
Following this, you need to request an access token for the profile. However, as of October 2020, you are no longer allowed to use a single authorization code for multiple access token grants. So you will need to login the user once more -- the canonical way of doing this is to simply navigate them back to the auth URL, leaving the login_hint field empty. This will vary depending on how you are constructing your URL, but here is an example in JS:
url = 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize?'
url += `client_id=${clientId}`
url += '&response_type=code'
url += '&redirect_uri=${redirectURI}'
url += '&response_mode=query'
url += '&login_hint='
url += '&scope=offline_access%20User.Read%20https%3A%2F%2Foutlook.office.com%2FIMAP.AccessAsUser.All%20https%3A%2F%2Foutlook.office.com%2FSMTP.Send'
url += '&state=12345
Note that your authorization code must request the full scope (including both User.Read and IMAP scopes like IMAP.AccessAsUser.All, for both access token requests. Specifying a smaller scope will not guarantee that the profile you read will necessarily correspond to the Outlook account.
After receiving this second authorization code (it won't ask the user to login manually again, just load a bit and automatically resolve a second code) you can request a new access token with the following scope:
user.read
You can include any other Graph API scopes above, but specifying something under Outlook and especially under IMAP will mix up your scopes. The response scope will still contain EAS access and Outlook scopes, but with the addition of the user.read permission.
You should use this second token to access the profile and refresh it separately from the first token (which should only be used for IMAP/SMTP).

Youtube (Google) List of approved scopes/permissions

I might be looking on a wrong source, but is here an endpoint for Youtube where I can list what scopes did the user approved? (This way I can make it so he needs to approve them if he is performing an action that he denied/revoked).
This is not possible there is no api that returns information about what scopes a user has granted
Autothizarion servers can return claims in their access tokens, refresh token, and or Id token. Sometimes this information contains the scopes granted. This depends highly on the authorization server setup. Googles doesn't return that. Your best bet is going to be to make the request and then request additional scopes if it fails

Is it feasible to use a Guid as an OAuth2 access token?

I am trying to see if I could get my OAuth2 provider to return a Guid as an access token. I am aware that there are existing and well-defined token providers and formats.
The resulting token would look like this:
{
access_token: "a31b99f9-01d7-7165-09be-73d5b7655f15",
expires_in: 1799,
token_type= "bearer"
}
I don't need to support claims and the rest of the authentication details will be stored somewhere in the back-end for when I need to validate it (check the expiry, retrieve additional details, etc). I'm just wondering if it's a feasible option as well?
Yes. Tokens maybe passed by "reference" as long as the Authorization Server supports OAuth 2.0 Token Introspection.
a GUID is not a token. The token includes information which you need to be able to retrieve and work with, otherwise what's the point in having it? The token includes information such as when it expires for example, among other things. If you don't know when the token expires how do you work with it?
You can use a GUID as your ClientID or ClientSecret ( or both ) for example, but that's about as far as you can take it.

Google OAuth2 - tokens, on-line, offline, adding scopes incrementally

Trying to organize this question into something clear. We are integrating Google for Work into our application, to use login, Google+, and eventually Contacts, Calendar, etc. As is recommended by Google and everything I have read, we are going to use incremental access, only adding scopes when they are needed. We are a PHP shop.
But, we will also be needing offline access, as our Contacts (and eventually Calendar) access will be synchronizing with our internal database.
We currently capture the Access and Refresh Tokens when doing the initial link, and store them locally, so that we can re-authorize at any time by using the Refresh token whenever the Access token expires. This is working correctly.
Questions:
a) when adding the incremental scopes for Contacts, the documentation says we need to call the gapi.auth.signIn() function in the page javascript with the new scopes. This is working on the page where we are allowing folks to manage settings. In the original login function callback, I save the Access Token and scopes with an Ajax call that uses the access code passed into the callback, and calls the Google_Client authenticate() function to get the access code and scopes... but at that point, the information I get back does not have the new scopes. Why? Do I have to re-extend the scopes every time the page is drawn?
b) since we are going to have a batch process do the contact synchronization, do I need to get an entirely different access token with access_type=offline, or can I use the current access token (properly extended with the new scopes). Can an off-line access token be used for on-line access as well as off-line? Or vice-versa?
For your questions:
a) have you used the parameter "include_granted_scopes"? as mentioned here:
https://developers.google.com/accounts/docs/OAuth2WebServer#incrementalAuth
b) When you request an offline access token, the response contains the access token and refresh token. so you can refresh the access token after it expires without having the user grant the permissions again.
online access token and offline access token work for the same.
the difference between both its the capability to refresh the access token when it expires without involving the user. Which is the functionality for the offline type.
The online access token doesn't mean that it works for your client-side authentication (done in the browser) and the offline works for the server-side.
You mentioned that you can get an access token, refresh token and authorization code from the client-side of your app. You could send that information to your server and make api calls from there, although this is not a good practice.
I would suggest that you do the OAuth Flow in the server side and from there manage the users information and API calls.
Here you can find the documentation on both Web server applications and Client Side applications.
Hope it's clearer.

Resources