Authorize Requests

Quoting from:

Every request your application sends to the Google Sheets API needs to identify your application to Google. There are two ways to identify your application: using an OAuth 2.0 token (which also authorizes the request) and/or using the application’s API key. Here’s how to determine which of those options to use:

  • If the request requires authorization (such as a request for an individual’s private data), then the application must provide an OAuth 2.0 token with the request. The application may also provide the API key, but it doesn’t have to.
  • If the request doesn’t require authorization (such as a request for public data), then the application must provide either the API key or an OAuth 2.0 token, or both—whatever option is most convenient for you.


Proposal: Always send an API key, i.e. just bake this into every request emitted by googlesheets. Consult the following sources for the key, in this order:

  1. Key specified directly in a gs_whatever() function call.
  2. Sys.getenv("GOOGLESHEETS_API_KEY"), which gives user a way to set this across multiple function calls, possibly at startup via .Renviron.
  3. getOption("googlesheets.api.key"), a fallback key baked into the package.

Currently implemented as api_key().


When will I send an OAuth2.0 token?

v3 post mortem

The Sheets API v3 has the notion of visibility:

The Sheets API v3 expresses visibility directly in its endpoints. A public spreadsheet has been “Published to the Web” and thus can be accessed by the API without authorization, while a private spreadsheet does require authentication.

Previously, I would inspect the endpoint URL. Presence of private versus public dictated that I would or would not send a token, respectively. But sometimes these URLs were, in fact, constructed by googlesheets itself. There was a moderate current towards building private URLs, even when public was possible. And that could lead to prompts to authenticate when it wasn’t strictly necessary.

This class of aggravation was further exacerbated by the gotcha re: Sheets being “Public on the web” vs “Published to the web”, which was not my fault (btw, I wonder if that’s still a problem?).

v4 planning

visibility is mercifully now gone:

In the new Sheets API v4, there is no explicit declaration of visibility. API calls are made using spreadsheet IDs. If the application does not have permission to access specified spreadsheet, an error is returned. Otherwise the call proceeds.

Thinking out loud:

  • Some endpoints or user-facing tasks will have a universal requirement (or perhaps lack?) for a token. Example of such an endpoint: sheets.spreadsheets.sheets.copyTo. Example of such a task: listing a user’s Sheets. Both of those will absolutely require a token. I will hardwire the inclusion of google_token() into requests built against such an endpoint or into the requests formed in such an operation.
  • For other endpoints or tasks, the need for a token can only be determined through knowledge of the authenticated user’s relationship to the target Sheet. So I need to make sure all necessary info is stored at registration time.
  • Open question: if I don’t know whether to send a token, do I default to “send if I have”? Or try-catch and retry with token on failure? Maybe this will never come up. Depends on how registration sorts out.