@azteam/google-api
Version:
N/A
232 lines (203 loc) • 7.33 kB
JavaScript
import jwt from 'jsonwebtoken';
import HttpClient from '@azteam/http-client';
import {ACCOUNT_TYPE} from './constant';
import * as SCOPE from './scope';
import {AUTH_EMAIL_SCOPE, AUTH_PROFILE_SCOPE} from './scope';
const OAUTH2_ENDPOINT = 'https://www.googleapis.com/oauth2/v3';
class GoogleOAuth2API {
static async getProfileInApp(appId, token) {
const client = new HttpClient({
timeout: 20000,
}),
res = await client.get(`${OAUTH2_ENDPOINT}/tokeninfo`, {
id_token: token,
});
if (res.azp && appId) {
return {
id: res.sub,
email: res.email,
name: res.name,
avatar: res.picture,
};
}
return null;
}
constructor(accountType, credential, options = {}) {
this.proxy = null;
if (options.proxy) {
this.proxy = {
host: options.proxy.ip,
port: options.proxy.port,
};
if (options.proxy.username) {
this.proxy.auth = {
username: options.proxy.username,
password: options.proxy.password,
};
}
}
this.accountType = accountType;
switch (this.accountType) {
case ACCOUNT_TYPE.SERVICE_ACCOUNT:
this.serviceAccountCredential = credential;
this.token = {
expiresAt: 0,
tokenType: 'Bearer',
accessToken: '',
};
break;
case ACCOUNT_TYPE.USER_ACCOUNT:
default:
this.clientId = credential.clientId;
this.clientSecret = credential.clientSecret;
if (credential.token) {
this.token = {
expiresAt: 0,
tokenType: 'Bearer',
...credential.token,
};
}
}
}
getAuthLinkFullScope(redirectURI, state) {
const scopeArray = Object.values(SCOPE);
return this.getAuthLink(redirectURI, state, scopeArray);
}
getAuthLink(redirectURI = 'http://localhost', state = null, arrayScope = [AUTH_EMAIL_SCOPE, AUTH_PROFILE_SCOPE]) {
const scopes = encodeURIComponent(arrayScope.join(' '));
return `https://accounts.google.com/o/oauth2/v2/auth/auth?access_type=offline&client_id=${this.clientId}&redirect_uri=${redirectURI}&response_type=code&scope=${scopes}&flowName=GeneralOAuthFlow&state=${state}`;
}
async getToken() {
return this.token;
}
async exchangeCode(code, redirectURI = 'http://localhost') {
const client = new HttpClient({
timeout: 20000,
}),
res = await client.post('https://oauth2.googleapis.com/token', {
code,
client_id: this.clientId,
client_secret: this.clientSecret,
redirect_uri: redirectURI,
grant_type: 'authorization_code',
});
if (res.access_token) {
this.token = {
accessToken: res.access_token,
refreshToken: res.refresh_token,
tokenType: res.token_type,
expiresAt: Date.now() + Number(res.expires_in) * 1000 - 600,
};
return this.token;
}
if (res.error) {
throw new Error(res.error);
}
return null;
}
async _getAuthClient() {
if (this.token) {
await this._refreshToken();
const clientOptions = {
timeout: 20000,
headers: {
Authorization: `${this.token.tokenType} ${this.token.accessToken}`,
},
};
if (this.proxy) {
clientOptions.proxy = this.proxy;
}
return new HttpClient(clientOptions);
}
throw new Error('Empty Init Token');
}
async getGoogleServiceAccessToken() {
const token = {
iss: this.serviceAccountCredential.client_email,
iat: Math.round(Date.now() / 1000),
exp: Math.round(Date.now() / 1000) + 60 * 60,
aud: `${OAUTH2_ENDPOINT}/token`,
scope: this.serviceAccountCredential.scope,
},
signedJwt = jwt.sign(token, this.serviceAccountCredential.private_key, {algorithm: 'RS256'}),
clientOptions = {
timeout: 20000,
headers: {
Authorization: `Bearer ${signedJwt}`,
},
};
if (this.proxy) {
clientOptions.proxy = this.proxy;
}
const client = new HttpClient(clientOptions);
return client.post(
token.aud,
{
grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',
assertion: signedJwt,
},
false
);
}
async getUserInfo() {
const client = await this._getAuthClient(),
res = await client.get(`${OAUTH2_ENDPOINT}/userinfo`);
if (res.error) {
throw new Error(res.error);
}
return res;
}
async getScope() {
const client = await this._getAuthClient(),
res = await client.get(`${OAUTH2_ENDPOINT}/tokeninfo`);
if (res.error) {
throw new Error(res.error);
}
if (res.scope) {
return res.scope.split(' ');
}
return [];
}
async hasScope(arrayScope = []) {
const scope = await this.getScope();
return scope.some((r) => arrayScope.includes(r));
}
async isLive() {
const client = await this._getAuthClient(),
res = await client.get(`${OAUTH2_ENDPOINT}/tokeninfo`);
return !res.error;
}
async _refreshToken() {
if (this.token.expiresAt < Date.now()) {
const clientOptions = {
timeout: 20000,
};
if (this.proxy) {
clientOptions.proxy = this.proxy;
}
const client = new HttpClient(clientOptions);
let res = null;
switch (this.accountType) {
case ACCOUNT_TYPE.SERVICE_ACCOUNT:
res = await this.getGoogleServiceAccessToken();
break;
case ACCOUNT_TYPE.USER_ACCOUNT:
default:
res = await client.post(`${OAUTH2_ENDPOINT}/token`, {
client_id: this.clientId,
client_secret: this.clientSecret,
refresh_token: this.token.refreshToken,
grant_type: 'refresh_token',
});
}
if (res.error) {
throw new Error(res.error);
}
this.token.accessToken = res.access_token;
this.token.tokenType = res.token_type;
this.token.expiresAt = Date.now() + Number(res.expires_in) * 1000 - 600;
}
return this.token;
}
}
export default GoogleOAuth2API;