Skip to content

Commit

Permalink
Implement useOAuth
Browse files Browse the repository at this point in the history
  • Loading branch information
LFDM committed Dec 26, 2020
1 parent 4cfc776 commit a8552c7
Showing 1 changed file with 60 additions and 0 deletions.
60 changes: 60 additions & 0 deletions lib/GoogleSpreadsheet.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,42 @@ const AUTH_MODES = {
JWT: 'JWT',
API_KEY: 'API_KEY',
RAW_ACCESS_TOKEN: 'RAW_ACCESS_TOKEN',
OAUTH: 'OAUTH'
};

const ONE_MINUTE = 60000;

const serializeParams = (params) => {
let options = "";
_.keys(params).forEach((key) => {
const isParamTypeObject = typeof params[key] === "object";
const isParamTypeArray = isParamTypeObject && params[key].length >= 0;
if (!isParamTypeObject)
options += `${key}=${encodeURIComponent(params[key])}&`;
if (isParamTypeObject && isParamTypeArray) {
_.each(params[key], (val) => {
options += `${key}=${encodeURIComponent(val)}&`;
});
}
});
return options ? options.slice(0, -1) : options;
};

const refreshToken = async ({ clientId, clientSecret, refreshToken }) => {
const url = "https://oauth2.googleapis.com/token";
const data = {
refresh_token: refreshToken,
client_id: clientId,
client_secret: clientSecret,
grant_type: "refresh_token",
};
const res = await Axios.post(url, serializeParams(data), {
headers: { "Content-Type": "application/x-www-form-urlencoded" },
});
return res.data;
};


class GoogleSpreadsheet {
constructor(sheetId) {
this.spreadsheetId = sheetId;
Expand Down Expand Up @@ -88,6 +122,12 @@ class GoogleSpreadsheet {
this.accessToken = token;
}

async useOAuthToken(creds, onRefreshTokens) {
this.authMode = AUTH_MODES.OAUTH;
this.oAuthCredentials = creds;
this.oAuthRefreshCallback = onRefreshTokens;
}

// creds should be an object obtained by loading the json file google gives you
// impersonateAs is an email of any user in the G Suite domain
// (only works if service account has domain-wide delegation enabled)
Expand Down Expand Up @@ -133,6 +173,26 @@ class GoogleSpreadsheet {
if (!this.apiKey) throw new Error('Please set API key');
config.params = config.params || {};
config.params.key = this.apiKey;
} else if (this.authMode === AUTH_MODES.OAUTH) {
const isExpired = !this.oAuthCredentials.expiresAt || this.oAuthCredentials.expiresAt < Date.now() - ONE_MINUTE * 2
if (isExpired) {
// refresh the token
const nextTokens = await refreshToken({
clientId: this.oAuthCredentials.clientId,
clientSecret: this.oAuthCredentials.clientSecret,
refreshToken: this.oAuthCredentials.refreshToken
})
this.oAuthCredentials.accessToken = nextTokens.access_token;
this.oAuthCredentials.refreshToken = nextTokens.refresh_token;
this.oAuthCredentials.expiresAt = Date.now() + nextTokens.expires_in * 1000;
await this.oAuthRefreshCallback({
accessToken: this.oAuthCredentials.accessToken,
refreshToken: this.oAuthCredentials.refreshToken,
expiresAt: this.oAuthCredentials.expiresAt
})
}

config.headers.Authorization = `Bearer ${this.oAuthCredentials.accessToken}`;
} else {
throw new Error('You must initialize some kind of auth before making any requests');
}
Expand Down

0 comments on commit a8552c7

Please sign in to comment.