Google Drive API Service Account - google-drive-realtime-api

I am trying to provide access to folders that have been created using a Rest API call using a Service account (The folders are created and the return values are proper).. but when I try to add a user delegation (using the sub in the JWT header), i keep getting a unauthorized user. I have checked the Service Account creation and everything seems right there. Any pointers?

Make sure that your request includes the Authorization header with a valid token. Try also to refresh your access token using the long-lived refresh token. If this fails, direct the user through the OAuth flow, as described in Authorizing Your App with Google Drive.
Check these links:
Google drive service account and "Unauthorized client or scope in request"
Ownership of Google Drive files and Service Account using API

Related

Forwarding OAuth 2 credentials from an authenticated request (in GCP specifically)

I have an AppEngine application that is behind an IAP (identity-aware proxy), so it receives requests that are authenticated and include a JWT token. From the AppEngine application I want to make a request to the Google Sheets API. That also requires an authenticated connection, but given that I want that connection to be made under the same user that accessed the application via the IAP, does anyone know how to create a request from inside the AppEngine application that will forward the token to Google Sheets? Cannot find any information on the subject... I am using Java, so any Java pointers would be appreciated, but general/other language help is good too...
I will describe the 2 approach proposed in the comment
The first one, to reuse the IAP proxy token to access Google Sheet is impossible, and dangerous.
Impossible because you receive an identity token from IAP (at least the requester/browser send an identity token to IAP) and you need an access token to request Sheet APIs.
Dangerous because, if you are able to reuse the IAP token to request the Google Sheet, that means the user is authorized to access to the Google Sheet. And I'm sure that you build an app to prevent any direct access/modification to the Google Sheet.
The second one, is to use a technical account (typically a service account) and generate an access token to access the Sheet API.
This second approach is the best one (don't forget to correctly log the user request and the subsequent sheet API calls in your AppEngine app to have the end to end traceability). BUT, and it's for that you ask this question, it's impossible with the App Engine default service account.
In fact, to access to the Sheet API, you need to scope your access token with the Sheet API. Sadly, you can't do this with App Engine. You can do this with Cloud Run, Cloud Functions, Compute Engine (without the default service account, else you need an extra config to achieve this with the Compute Engine default service account). But not with App Engine.
So, you have 2 solutions:
Either you use another hosting platform (Cloud Run for example), but you loose the IAP capacity (for now)
You continue to use App Engine but you need to request an access token to another service account (it's not required to have a service account key file). You can use the Service Account Credential API for this. I wrote an article on this API
Note: later in 2021, App Engine should be able to accept custom service account, and thus the issue should be solved

Is there a way to get a list of Azure AD tenants from within a service principal?

I have created an app to get various information from Azure AD, such as users and groups. It lives in one of my tenants as an app registration. This works fine, but now I would also like my app to get a list of the ids of other tenants I have in my account.
I have given my app user_impersonation permission on Azure Service Management, and I am able to make
GET https://management.azure.com/tenants?api-version=2016-06-01 requests using my client credentials. However, when I make that call I get a list only containing the tenant that my app/service principal lives in. Is there a way I can use this API call to see other tenant ids from within my app?
Yes, you could do that with auth code flow instead of client credentials flow.
Since you are trying to get the tenants of your account rather than the app/service principal, you have to include the account information when doing the authentication.
Client credentials flow is App-only. Auth code flow is App+user.
See reference here to learn how to implement Authorization code grant (interactive clients).
And here is the document about OAuth 2.0 authorization code flow.
You need to Request an authorization code first and then Request an access token with the code from the previous step. Using this access token, you can list the tenants you have in your account.

How to get scope list from service for specifying with client authentication request

I have a UWP app that uses WebAccountManager for AAD authentication. I also have a service, hosted in Azure, used by the UWP app. That service uses the token the UWP app sends to get another on-behalf-of token (I think that's what it's called) to then call other service APIs as the user (e.g. Microsoft Graph and Outlook REST API). In other words, UWP app calls WebAuthenticationCoreManager.RequestTokenAsync to get a token, sends it to my service, my service calls AuthenticationContext.AcquireTokenAsync to get an on-behalf-of token to use when calling the Outlook REST API, for example.
In the AAD registration for my service, the "Required Permissions" list all the services and permissions/API calls it might make on behalf of the user (E.g. "Microsoft Graph"-> "Have full access to user calendars")
When my UWP app creates the WebTokenRequest to pass into the RequestTokenAsync function, it currently passes an empty string as the value for "scope." What should it be passing for the scope parameter? Should it be passing the full and exact list of permissions that the service declares are required? If so, how do I get that permission list to the client? Just hard-code and update the list whenever the service required permissions list changes?
In Azure Active Directory, there are two fundamentally different ways to specify the permissions your app requires when authenticating.
Static Consent
Dynamic Consent
Back in the Azure Active Directory V1 endpoint, you would set "Required Permissions" to other APIs when registering your client application. This is setting up Static Consent. These permissions are fixed, and when you trigger the user to consent to these permissions, the user has to consent to them all at once. Additionally, if at some point your app wants to add new permissions to other APIs, you will need to force the user to go through the full consent experience again, which may even require special logic on your application.
This is why in the V2 endpoint, Microsoft developed Incremental and dynamic consent.
With the v2.0 endpoint, you can specify the permissions your app needs dynamically, at runtime, during regular usage of your app. To do so, you can specify the scopes your app needs at any given point in time by including them in the scope parameter of an authorization request.
Here, you can specify only the permissions your app needs to complete the flows it is trying to accomplish at that time. If you need more access, you can simply add it during your authentication experience, and it will prompt the user only for those new permissions.
Now let's return to your question. If you are using the V2 endpoint, you should be using Dynamic Consent, which means that the settings in "Required Permissions" do not really matter to you. You should be keeping the list of scopes your app requires in your app settings.
Some situations in the V2 endpoint still require Static Consent, like service to service calls with direct application permissions. For those situations you would pass the scope <resource>/.default as noted here. This might also work for delegated tokens, but it is better to just use Dynamic Consent.

appengine access via oauth2 python script (replacing ClientLogin)

I have an App Engine project which:
uses google.appengine.api.get_current_user() to handle users (and login:required)
has a URL to collect some data (which requires login)
has Google users but on a custom domain
I used to have a script to pull the data using the old https://www.google.com/accounts/ClientLogin interface, but now that interface is deprecated, I'm trying to work out what I need to do to get OAuth2 working to access my App Engine URL with a user value set.
I have worked my way through OAuth2 for devices to get myself an access key for my script (i.e. I can run it, authenticate in a web browser, then poll for the access key), as described in OAuth2 For Devices.
But I'm not sure:
what scope I should be using to request the access_token compatible with get_current_user(),
how to pass this in my request to App Engine so that it can create the the user header, and
whether I need to modify my app to use this access_token, eg adding callbacks etc
With regards to the last point, user was set by google's front end infrastructure so I’m hoping that that same infrastructure can somehow convert my OAuth access_token into a login name without me needing to update my app to do the callback part, because it should all be in appengine's infrastructure right and user is set before the request comes to my app.

Server-side OAuth for user impersonation via GMail API

I am trying to perform server-side OAuth so I can use a specific user account in my domain to send emails (hence using GMail API) via my application.
Mine is a purely server-side app and I cannot perform "user consent" via a UI.
I have created a project in Google App Engine and have obtained service account credentials (P12 key).
My code looks like this -
new GoogleCredential.Builder()
.setTransport(httpTransport)
.setJsonFactory(JSON_FACTORY)
.setServiceAccountId(googleEmailerServiceAccountId)
.setServiceAccountPrivateKeyFromP12File(new File(googleEmailerServiceAccountPrivateKeyLocation)).setServiceAccountScopes(Collections.singleton(GmailScopes.GMAIL_COMPOSE))
.setServiceAccountUser("xxx#xxx.com")
.build()
I have delegated domain wide access to the application (for GMAIL COMPOSE scope) via the admin console as per https://developers.google.com/identity/protocols/OAuth2ServiceAccount.
And I still get an Unauthorised 401 when I try to send emails from my app.
Since there is no explicit documentation for the Gmail API that says it allows domain wide delegation, I am guessing it is not allowed for Gmail.
Is there any way of achieving this programatically?
Any idea would be much appreciated.
Thanks!
As far as I know you cant use a service account with Gmail. Service accounts must be pre authorized.
Authorizing Your App with Gmail
All requests to the Gmail API must be authorized by an authenticated
user. Gmail uses the OAuth 2.0 protocol for authenticating a Google
account and authorizing access to user data. You can also use Google+
Sign-in to provide a "sign-in with Google" authentication method for
your app.
Share a Google drive folder with the Service account. Add the service account email as a user on a google drive folder it has access
Share a Google calendar with the service account, just like any other user.
Service accounts don't work on all Google APIs. To my knowledge you cant give another user access to your Gmail so there will be now to pre authorize the service account.
Recommendation / work around / hack
Create a dummy app using the same client id, authenticate it get the refresh token then use the refresh token in your application.

Resources