title: Is it possible to retrieve an OAuth2 access token from Google with client secret file of Google Apps Script project?
body: <p>I want to <em>reuse</em> 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.</p>
  
  <p>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?</p>
  
  <h2>Client secrets of the script</h2>
  
  <ol>
  <li>OAuth2 client-secret file of the script from <a href="https://console.developers.google.com/apis/credentials?showWizardSurvey=true" rel="nofollow noreferrer">Google API Console, under Credentials</a>. Also see <a href="https://support.google.com/googleapi/answer/6158857?hl=en-GB" rel="nofollow noreferrer">Credentials, access, security, and identity</a> and <a href="https://support.google.com/googleapi/answer/6158849" rel="nofollow noreferrer">Setting up OAuth 2.0</a></li>
  </ol>
  
  <p>The client-secrets.json looks like this:</p>
  
  <pre><code>{"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"]
  }}
  </code></pre>
  
  <p>The file would be deployed with the app code (App Engine). But an alternate location such as Cloud Storage would be possible.</p>
  
  <h2>OAuth2 access token</h2>
  
  <p>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:</p>
  
  <pre><code>HTTP 200 OK
  Content-type: application/json
  {
  "access_token": "987tghjkiu6trfghjuytrghj",
  "scope": "foo bar",
  "token_type": "Bearer"
  }
  </code></pre>
  
  <p>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.</p>
  
  <h2>Client_credentials request to authorization server</h2>
  
  <p>My (limited) understanding is, that I can use the grant-type <code>client_credentials</code> to get the access token from the authorization server. The request would look like this:</p>
  
  <pre><code>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&amp;
  scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fspreadsheets
  </code></pre>
  
  <p>Where the Basic HTTP authorization is <code>client_id:client_secret</code> values, separated by a colon, and base64 encoded.</p>
  
  <p>If I ditch <code>grant_type</code> or <code>scope</code> in the body, I will get corresponding errors.</p>
  
  <p>The version as above resulted in: <code>{\n  "error" : "invalid_request"\n}</code> response, no specifics provided. I have tried with <code>client_id</code> and <code>client_secret</code> in the body in combination with and without the Authorization header, all with the same error.</p>