Skip to content

Commit

Permalink
version 3.1.15 - oauth support
Browse files Browse the repository at this point in the history
  • Loading branch information
theoephraim authored and Theo Ephraim committed Nov 6, 2021
1 parent 197e351 commit b11da48
Show file tree
Hide file tree
Showing 9 changed files with 83 additions and 83 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ node_modules/
ignore/
.env
.DS_Store
examples/
examples/
TODO
20 changes: 6 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
[![Known Vulnerabilities](https://snyk.io/test/github/theoephraim/node-google-spreadsheet/badge.svg?targetFile=package.json)](https://snyk.io/test/github/theoephraim/node-google-spreadsheet?targetFile=package.json)
[![NPM](https://img.shields.io/npm/dw/google-spreadsheet)](https://www.npmtrends.com/google-spreadsheet)

- multiple auth options - API key, service account, oauth
- multiple auth options - service account (w/ optional impersonation), OAuth 2.0, API key (read-only)
- cell-based API - read, write, bulk-updates, formatting
- row-based API - read, update, delete (based on the old v3 row-based calls)
- managing worksheets - add, remove, resize, change title, formatting
Expand All @@ -16,7 +16,7 @@ Full docs available at [https://theoephraim.github.io/node-google-spreadsheet](h

> **🚨 Google Deprecation Warning - affects older version (v2) of this module 🚨**
>
> Google is [phasing out their old v3 api](https://cloud.google.com/blog/products/g-suite/migrate-your-apps-use-latest-sheets-api), which the older version of this module used to use. Originally they were going to shut it down on March 3rd 2020, but have pushed that date back to January 2021.
> Google is [phasing out their old v3 api](https://cloud.google.com/blog/products/g-suite/migrate-your-apps-use-latest-sheets-api), which the older version of this module used. Originally they were going to shut it down on March 3rd 2020, but have pushed that date back to June 2021.

**Regardless, please upgrade to the latest version of this module (v3) which uses the newer sheets v4 API**
Expand All @@ -28,7 +28,7 @@ Full docs available at [https://theoephraim.github.io/node-google-spreadsheet](h
## Examples
_the following examples are meant to give you an idea of just some of the things you can do_

!> NOTE - To keep the examples more concise, I'm calling await [at the top level](https://v8.dev/features/top-level-await) which is not allowed by default in most versions of node. If you need to call await in a script at the root level, you must instead wrap it in an async function like so:
> **IMPORTANT NOTE** - To keep the examples concise, I'm calling await [at the top level](https://v8.dev/features/top-level-await) which is not allowed by default in most versions of node. If you need to call await in a script at the root level, you must instead wrap it in an async function like so:
```javascript
(async function() {
Expand All @@ -41,22 +41,14 @@ _the following examples are meant to give you an idea of just some of the things
```javascript
const { GoogleSpreadsheet } = require('google-spreadsheet');

// spreadsheet key is the long id in the sheets URL
// Initialize the sheet - doc ID is the long id in the sheets URL
const doc = new GoogleSpreadsheet('<the sheet ID from the url>');

// use service account creds
// Initialize Auth - see more available options at https://theoephraim.github.io/node-google-spreadsheet/#/getting-started/authentication
await doc.useServiceAccountAuth({
client_email: process.env.GOOGLE_SERVICE_ACCOUNT_EMAIL,
private_key: process.env.GOOGLE_PRIVATE_KEY,
});
// OR load directly from json file if not in secure environment
await doc.useServiceAccountAuth(require('./creds-from-google.json'));
// OR use service account to impersonate a user (see https://developers.google.com/identity/protocols/oauth2/service-account#delegatingauthority)
await doc.useServiceAccountAuth(require('./creds-from-google.json'), '[email protected]');
// OR use a pre-configured Google OAuth2Client (check the Authentication docs for more info)
doc.useOAuth2Client(oAuth2Client);
// OR use API key -- only for read-only access to public sheets
doc.useApiKey('YOUR-API-KEY');

await doc.loadInfo(); // loads document properties and worksheets
console.log(doc.title);
Expand Down Expand Up @@ -152,7 +144,7 @@ None yet - get in touch!

Contributions are welcome, but please follow the existing conventions, use the linter, add relevant tests, add relevant documentation.

These docs are generated using [docsify](https://docsify.js.org). To preview and run locally so you can make edits, run `npm run docs:preview` and head to http://localhost:3000
The docs site is generated using [docsify](https://docsify.js.org). To preview and run locally so you can make edits, run `npm run docs:preview` and head to http://localhost:3000
The content lives in markdown files in the docs folder.

## License
Expand Down
19 changes: 7 additions & 12 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<!-- DO NOT EDIT THIS FILE, EDIT MAIN README.md AND RUN `npm readme:copy` instead -->

_Welcome to the docs site for_

# google-spreadsheet
> The most popular [Google Sheets API](https://developers.google.com/sheets/api/reference/rest) wrapper for javascript
Expand All @@ -9,7 +10,7 @@
[![Known Vulnerabilities](https://snyk.io/test/github/theoephraim/node-google-spreadsheet/badge.svg?targetFile=package.json)](https://snyk.io/test/github/theoephraim/node-google-spreadsheet?targetFile=package.json)
[![NPM](https://img.shields.io/npm/dw/google-spreadsheet)](https://www.npmtrends.com/google-spreadsheet)

- multiple auth options - API key, service account, oauth
- multiple auth options - service account (w/ optional impersonation), OAuth 2.0, API key (read-only)
- cell-based API - read, write, bulk-updates, formatting
- row-based API - read, update, delete (based on the old v3 row-based calls)
- managing worksheets - add, remove, resize, change title, formatting
Expand All @@ -19,7 +20,7 @@ Full docs available at [https://theoephraim.github.io/node-google-spreadsheet](h

> **🚨 Google Deprecation Warning - affects older version (v2) of this module 🚨**
>
> Google is [phasing out their old v3 api](https://cloud.google.com/blog/products/g-suite/migrate-your-apps-use-latest-sheets-api), which the older version of this module used to use. Originally they were going to shut it down on March 3rd 2020, but have pushed that date back to January 2021.
> Google is [phasing out their old v3 api](https://cloud.google.com/blog/products/g-suite/migrate-your-apps-use-latest-sheets-api), which the older version of this module used. Originally they were going to shut it down on March 3rd 2020, but have pushed that date back to June 2021.

**Regardless, please upgrade to the latest version of this module (v3) which uses the newer sheets v4 API**
Expand All @@ -31,7 +32,7 @@ Full docs available at [https://theoephraim.github.io/node-google-spreadsheet](h
## Examples
_the following examples are meant to give you an idea of just some of the things you can do_

!> NOTE - To keep the examples more concise, I'm calling await [at the top level](https://v8.dev/features/top-level-await) which is not allowed by default in most versions of node. If you need to call await in a script at the root level, you must instead wrap it in an async function like so:
> **IMPORTANT NOTE** - To keep the examples concise, I'm calling await [at the top level](https://v8.dev/features/top-level-await) which is not allowed by default in most versions of node. If you need to call await in a script at the root level, you must instead wrap it in an async function like so:
```javascript
(async function() {
Expand All @@ -44,20 +45,14 @@ _the following examples are meant to give you an idea of just some of the things
```javascript
const { GoogleSpreadsheet } = require('google-spreadsheet');

// spreadsheet key is the long id in the sheets URL
// Initialize the sheet - doc ID is the long id in the sheets URL
const doc = new GoogleSpreadsheet('<the sheet ID from the url>');

// use service account creds
// Initialize Auth - see more available options at https://theoephraim.github.io/node-google-spreadsheet/#/getting-started/authentication
await doc.useServiceAccountAuth({
client_email: process.env.GOOGLE_SERVICE_ACCOUNT_EMAIL,
private_key: process.env.GOOGLE_PRIVATE_KEY,
});
// OR load directly from json file if not in secure environment
await doc.useServiceAccountAuth(require('./creds-from-google.json'));
// OR use service account to impersonate a user (see https://developers.google.com/identity/protocols/oauth2/service-account#delegatingauthority)
await doc.useServiceAccountAuth(require('./creds-from-google.json'), '[email protected]');
// OR use API key -- only for read-only access to public sheets
doc.useApiKey('YOUR-API-KEY');

await doc.loadInfo(); // loads document properties and worksheets
console.log(doc.title);
Expand Down Expand Up @@ -153,7 +148,7 @@ None yet - get in touch!

Contributions are welcome, but please follow the existing conventions, use the linter, add relevant tests, add relevant documentation.

These docs are generated using [docsify](https://docsify.js.org). To preview and run locally so you can make edits, run `npm run docs:preview` and head to http://localhost:3000
The docs site is generated using [docsify](https://docsify.js.org). To preview and run locally so you can make edits, run `npm run docs:preview` and head to http://localhost:3000
The content lives in markdown files in the docs folder.

## License
Expand Down
26 changes: 21 additions & 5 deletions docs/classes/google-spreadsheet.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,8 @@ Param|Type|Required|Description

-**Side effects** - all requests will now authenticate using these credentials

> See [Getting Started > Authentication](getting-started/authentication) for more details
> See [Getting Started > Authentication > Service Account](getting-started/authentication#service-account) for more details
http://localhost:3000/#/getting-started/authentication?id=service-account

#### `useApiKey(key)` :id=fn-useApiKey
> Set API-key to use for auth - only allows read-only access to public docs
Expand All @@ -103,18 +103,34 @@ Param|Type|Required|Description

-**Side effects** - all requests will now authenticate using this api key only

> See [Getting Started > Authentication](getting-started/authentication) for more details
> See [Getting Started > Authentication > API Key](getting-started/authentication#api-key) for more details

#### `useOAuth2Client(oAuth2Client)` :id=fn-useOAuth2Client
> Use [Google's OAuth2Client](https://github.com/googleapis/google-auth-library-nodejs#oauth2) to authenticate on behalf of a user
Param|Type|Required|Description
---|---|---|---
`oAuth2Client`|OAuth2Client|✅|Configured OAuth2Client

-**Side effects** - requests will use oauth access token to authenticate requests. New access token will be generated if token is expired.

> See [Getting Started > Authentication > OAuth 2.0](getting-started/authentication#oauth) for more details

#### `useRawAccessToken(token)` :id=fn-useRawAccessToken
> Set token to use for auth - managed elsewhere
> Set raw token to use for auth - managed elsewhere
Param|Type|Required|Description
---|---|---|---
`token`|String|✅|Oauth token to use

-**Side effects** - all requests will now authenticate using this api key only

!> This assumes you are creating and managing/refreshing the token yourself. Deeper oauth support coming soon...
!> This assumes you are creating and managing/refreshing the token yourself




### Basic info

Expand Down
58 changes: 42 additions & 16 deletions docs/getting-started/authentication.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ You have several options for how you want to connect, but most projects should u

- [Service Account](#service-account) - connects as a specific "bot" user generated by google for your application
- [API-key](#api-key) - only identifies your application, provides read-only access
- [OAuth](#oauth) - connect on behalf of a specific user
- [OAuth](#oauth) - connect on behalf of a specific user using OAuth

**👉 BUT FIRST -- Set up your google project & enable the sheets API 👈**
1. Go to the [Google Developers Console](https://console.developers.google.com/)
Expand All @@ -25,7 +25,7 @@ This is a 2-legged oauth method and designed to be "an account that belongs to y
Use this for an app that needs to access a set of documents that you have full access to, or can at least be shared with your service account.
([read more](https://developers.google.com/identity/protocols/OAuth2ServiceAccount))

You may also grant your service account ["domain-wide delegation"](https://developers.google.com/identity/protocols/oauth2/service-account#delegatingauthority) which enables it to impersonate any user within your org. This can be helpful if you need to connect on behalf of users only within your organization.
You may also grant your service account ["domain-wide delegation"](https://developers.google.com/identity/protocols/oauth2/service-account#delegatingauthority) which enables it to impersonate any user within your org. This can be helpful if you need to connect on behalf of users _only within your organization_.

__Setup Instructions__

Expand Down Expand Up @@ -80,7 +80,7 @@ Google requires this so they can at least meter your usage of their API.
__Setup Instructions__
1. Follow steps above to set up project and enable sheets API
2. Create an API key for your project
- In the sidebar on the left, select **Credentials**
- Navigate to the [credentials section of the google developer console](https://console.cloud.google.com/apis/credentials)
- Click blue "+ CREATE CREDENITALS" and select "API key" option
- Copy the API key
3. OPTIONAL - click "Restrict key" on popup to set up restrictions
Expand All @@ -98,32 +98,58 @@ doc.useApiKey(process.env.GOOGLE_API_KEY);
## 👨‍💻 OAuth 2.0 :id=oauth
**connect on behalf of a user with an Oauth token**

Use [Google's OAuth2Client](https://github.com/googleapis/google-auth-library-nodejs#oauth2) to authenticate.
Use [Google's OAuth2Client](https://github.com/googleapis/google-auth-library-nodejs#oauth2) to authenticate.

Handling Oauth and how it works is out of scope of this project - but the info you need can be found [here](https://developers.google.com/identity/protocols/oauth2).

Nevertheless, here is a rough outline of what to do with a few tips:
1. Follow steps above to set up project and enable sheets API
2. Create OAuth 2.0 credentials for your project (**these are not the same as the service account credentials described above**)
- Navigate to the [credentials section of the google developer console](https://console.cloud.google.com/apis/credentials)
- Click blue "+ CREATE CREDENITALS" and select "Oauth Client ID" option
- Select your application type and set up authorized domains / callback URIs
- Record your client ID and secret
- You will need to go through an Oauth Consent screen verification process to use these credentials for a production app with many users
3. For each user you want to connect on behalf of, you must get them to authorize your app which involves asking their permissions by redirecting them to a google-hosted URL
- generate the oauth consent page url and redirect the user to it
- there are many tools, [google provided](https://github.com/googleapis/google-api-nodejs-client#oauth2-client) and [more](https://www.npmjs.com/package/simple-oauth2) [generic](https://www.npmjs.com/package/hellojs) or you can even generate the URL yourself
- make sure you use the credentials generated above
- make sure you include the [appropriate scopes](https://developers.google.com/identity/protocols/oauth2/scopes#sheets) for your application
- the callback URL (if successful) will include a short lived authorization code
- you can then exchange this code for the user's oauth tokens which include:
- an access token (that expires) which can be used to make API requests on behalf of the user, limited to the scopes requested and approved
- a refresh token (that does not expire) which can be used to generate new access tokens
- save these tokens somewhere secure like a database (ideally you should encrypt these before saving!)
4. Initialize an OAuth2Client with your apps oauth credentials and the user's tokens, and pass the client to your GoogleSpreadsheet object


```javascript
// clientId and clientSecret are required to refresh the access token automatically
const = oAuth2Client = new OAuth2Client({
const { OAuth2Client } = require('google-auth-library');

// Initialize the OAuth2Client with your app's oauth credentials
const oauthClient = new OAuth2Client({
clientId: process.env.GOOGLE_OAUTH_CLIENT_ID,
clientSecret: process.env.GOOGLE_OAUTH_CLIENT_SECRET
})
});

// Pre-configure the client with credentials you have stored in e.g. your databse
// At a minimum, provide only the refresh_token. The client will use it to retrieve
// a fresh access_token, with a fresh expiration date.
oAuth2Client.credentials.access_token = accessToken;
oAuth2Client.credentials.refresh_token = refreshToken;
oAuth2Client.credentials.expiry_date = expiryDate; // Unix epoch milliseconds
// Pre-configure the client with credentials you have stored in e.g. your database
// NOTE - refresh_token is required, whilt the access token and expiryDate are optional
// (the refresh token is used to generate a missing/expired access token)
const { accessToken, refreshToken, expiryDate } = await fetchUserGoogleCredsFromDatabase();
oauthClient.credentials.access_token = accessToken;
oauthClient.credentials.refresh_token = refreshToken;
oauthClient.credentials.expiry_date = expiryDate; // Unix epoch milliseconds

// Listen in whenever a new access token is obtained. You might want to store them in your database.
// Mind that the refresh_token never changes (unless it's revoked, in which case your end-user will
// need to go through the full authentication flow again), so storing the new access_token is optional.
oAuth2Client.on('tokens', credentials => {
// need to go through the full authentication flow again), so storing the new access_token is optional.
oauthClient.on('tokens', credentials => {
console.log(credentials.access_token);
console.log(credentials.scope);
console.log(credentials.expiry_date);
console.log(credentials.token_type); // will always be 'Bearer'
})

const doc = new GoogleSpreadsheet('<YOUR-DOC-ID>');
doc.useOAuth2Client(oauth2Client);
doc.useOAuth2Client(oauthClient);
```
21 changes: 0 additions & 21 deletions docs/getting-started/limitations.md

This file was deleted.

Loading

0 comments on commit b11da48

Please sign in to comment.