@integromat/proto-oauth
Version:
Integromat OAuth Proto-Classes
159 lines (127 loc) • 4.13 kB
JavaScript
'use strict'
const request = require('request');
const crypto = require('crypto');
const qs = require('qs');
class OAuth2Client {
constructor (options){
if (typeof options !== 'object') {
throw new Error('Undefined is not a valid options object.');
}
this.clientId = options.clientId;
this.clientSecret = options.clientSecret;
this.authorizeUri = options.authorizeUri;
this.tokenUri = options.tokenUri;
this.redirectUri = options.redirectUri;
this.customHeaders = options.customHeaders || {};
this.accessTokenType = options.accessTokenType || 'Bearer';
this.scopeSeparator = options.scopeSeparator || ',';
this.useAuthHeader = options.useAuthHeader || true;
this.useState = options.useState || true;
this.addAuthorizeParameters = options.addAuthorizeParameters || {}
this.addAccessTokenParameters = options.addAccessTokenParameters || {}
this.addRefreshTokenParameters = options.addRefreshTokenParameters || {}
if (this.useState) this.state = crypto.randomBytes(10).toString('hex');
if (!Object.keys(this.customHeaders).find(k => /User-Agent/i.test(k)))
this.customHeaders['User-Agent'] = `Integromat/${process.env.IMT_ENV || 'local'}`
}
setAccessTokenName (name){
this.accessTokenName = name;
}
setAccessTokenType (type){
this.accessTokenType = type;
}
setScopeSeparator (separator){
this.scopeSeparator = separator;
}
useAuthHeader (use){
this.useAuthHeader = options.useAuthHeader;
}
_buildAuthHeader (token) {
return `${this.accessTokenType} ${token}`;
}
_getDefaultAuthorizeParameters (){
let params = {
response_type: 'code',
client_id: this.clientId,
redirect_uri: this.redirectUri
};
Object.assign(params, this.addAuthorizeParameters);
if (this.useState) params.state = this.state;
return params;
}
_getDefaultAccessTokenParameters (code){
let params = {
grant_type: 'authorization_code',
code,
redirect_uri: this.redirectUri,
client_id: this.clientId,
client_secret: this.clientSecret
};
Object.assign(params, this.addAccessTokenParameters);
return params;
}
_getDefaultRefreshTokenParameters (refreshToken){
let params = {
grant_type: 'refresh_token',
refresh_token: refreshToken,
client_id: this.clientId,
client_secret: this.clientSecret
};
Object.assign(params, this.addRefreshTokenParameters);
return params;
}
_buildUrlWithQuery(baseUrl, queryObj) {
const url = new URL(baseUrl);
for (const [key, value] of Object.entries(queryObj)) {
url.searchParams.append(key, value);
}
return url.toString();
};
getAuthorizeUrl(scope) {
scope = scope || [];
if (Array.isArray(scope)) {
let query = this._getDefaultAuthorizeParameters();
if (scope.length > 0)
query.scope = scope.join(this.scopeSeparator);
return this._buildUrlWithQuery(this.authorizeUri, query);
}
scope.client_id = this.clientId;
return this._buildUrlWithQuery(this.authorizeUri, scope);
}
_request (params, done){
request({
uri: this.tokenUri,
method: 'POST',
json: true,
form: params,
headers: this.customHeaders
},
done);
}
getAccessToken (code, done){
if (typeof code === 'object'){
code.client_id = this.clientId;
code.client_secret = this.clientSecret;
return this._request(code, done);
}
return this._request(this._getDefaultAccessTokenParameters(code), done);
}
getRefreshToken (refreshToken, done){
if (typeof refreshToken === 'object') {
refreshToken.client_id = this.clientId;
refreshToken.client_secret = this.clientSecret;
return this._request(refreshToken, done);
}
return this._request(this._getDefaultRefreshTokenParameters(refreshToken), done);
}
_secureRequest (method, accessToken){
return request.defaults({
method: method,
json: true,
headers: Object.assign({ 'Authorization': this._buildAuthHeader(accessToken) }, this.customHeaders)
});
}
get (options, accessToken, done){ this._secureRequest('GET', accessToken)(options, done); }
post (options, accessToken, done){ this._secureRequest('POST', accessToken)(options, done); }
}
module.exports = OAuth2Client;