Search code examples
oauth-2.0google-apigoogle-sheets-apigoogle-oauthgoogle-identity

Is it possible to retrieve an OAuth2 access token from Google with client secret file of Google Apps Script project?


I want to reuse the OAuth2 client-secret of a Google Apps script project to access Google APIs on behalf of this script (e.g. via Sheets API reading a spreadsheet where the script has access). Users with a Google account granted the necessary scopes to the script. Now I'd like to replace the script with a new app without asking the users again for user consent. Typically, when the script (or the app) runs the users would be offline.

My first question would be, if this scenario is a supported OAuth2 use-case with Google API authorization, and if so, what would be the best way to implement it, especially to prevent security issues?

Client secrets of the script

  1. OAuth2 client-secret file of the script from Google API Console, under Credentials. Also see Credentials, access, security, and identity and Setting up OAuth 2.0

The client-secrets.json looks like this:

{"web":{
"client_id": "57...1t.apps.googleusercontent.com",
"project_id": "project-id-95...70",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://accounts.google.com/o/oauth2/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_secret": "K2...y1",
"redirect_uris": ["https://script.google.com/oauthcallback"]
}}

The file would be deployed with the app code (App Engine). But an alternate location such as Cloud Storage would be possible.

OAuth2 access token

In absence of the user, I would like to use the client ID and secret with the same scopes that were granted to the script originally, for getting an access token from the Google authorization server, something like this:

HTTP 200 OK
Content-type: application/json
{
"access_token": "987tghjkiu6trfghjuytrghj",
"scope": "foo bar",
"token_type": "Bearer"
}

I would like to use the access token in the HTTP Bearer header for the requests to the Sheets API on behalf of the old script.

Client_credentials request to authorization server

My (limited) understanding is, that I can use the grant-type client_credentials to get the access token from the authorization server. The request would look like this:

POST /o/oauth2/token
Host: https://accounts.google.com
Content-Type: application/x-www-form-urlencoded
Accept: application/json
Authorization: Basic Base_64_string

grant_type=client_credentials&
scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fspreadsheets

Where the Basic HTTP authorization is client_id:client_secret values, separated by a colon, and base64 encoded.

If I ditch grant_type or scope in the body, I will get corresponding errors.

The version as above resulted in: {\n "error" : "invalid_request"\n} response, no specifics provided. I have tried with client_id and client_secret in the body in combination with and without the Authorization header, all with the same error.


Solution

  • First Off let me start by saying that i am not an expert in app script or sheets i have used both a few times but i dont consider myself an expert in the subject.

    When you authenticate someone their authentication is granted based upon the client id from within a project. They are granting you access to their data and approving the credential request. Think of it as a recored in Googles database someplace.

    User 321 has granted consent to client 123 to access their sheets data.

    So you have a project Super Script App which has client id 123 you are asking for access to edit sheets. If i approve it i am giving Super Script App with client id 123 access to my sheets. While i am sitting at my machine your app will run accessing my data. Now when i log off Super Script App with client id 123 cant access my data unless you have offline access and have a refresh token. With that refresh token you will be able to access my data when i am not there by requesting a new access token.

    Now you want to make a new app. If you take the client id 123 and use it in your new app I am going to have to login to my google account but it will not popup and request that i give you permissions to access my data I have already granted client id 123 access to my sheets. Unless you have a refresh token your not going to be able to access this data without me being there.

    If at anytime you ask for an extra scope I am going to have to approve that.

    Now comes the fun part. I haven't actually tried this in a while. If you go to Google Developer console and create client id 321 under the same project as client id 123, and then use that in your new Super Script App V2 will i still have to grant it permission to access my data? I am going to lean towards probably not. Note a refresh token created with client id 123 will not work with client id 321 they are locked to a client unless its mobile and there is some magic their.

    I am not exactly sure what you are doing with your second app so i hope this helps clear things up.