Files
biomedjs/node_modules/googleapis/lib/auth/oauth2client.js
2014-09-14 07:04:16 -04:00

200 lines
5.5 KiB
JavaScript

/**
* Copyright 2012 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var querystring = require('querystring');
var AuthClient = require('./authclient.js');
var util = require('util');
function OAuth2Client(clientId, clientSecret, redirectUri, opt_opts) {
OAuth2Client.super_.call(this);
this.clientId_ = clientId;
this.clientSecret_ = clientSecret;
this.redirectUri_ = redirectUri;
this.opts = opt_opts || {};
this.credentials = null;
}
/**
* Inherit from AuthClient.
*/
util.inherits(OAuth2Client, AuthClient);
/**
* The base URL for auth endpoints.
* @const
* @private
*
*/
OAuth2Client.GOOGLE_OAUTH2_AUTH_BASE_URL_ =
'https://accounts.google.com/o/oauth2/auth';
/**
* The base endpoint for token retrieval.
* @const
* @private
* The ..
*/
OAuth2Client.GOOGLE_OAUTH2_TOKEN_URL_ =
'https://accounts.google.com/o/oauth2/token';
/**
* The base endpoint to revoke tokens.
* @const
* @private
*/
OAuth2Client.GOOGLE_OAUTH2_REVOKE_URL_ =
'https://accounts.google.com/o/oauth2/revoke';
/**
* Generates URL for consent page landing.
* @param {object=} opt_opts Options.
* @return {string} URL to consent page.
*/
OAuth2Client.prototype.generateAuthUrl = function(opt_opts) {
var opts = opt_opts || {};
opts.response_type = opts.response_type || 'code';
opts.client_id = this.clientId_;
opts.redirect_uri = this.redirectUri_;
var rootUrl = this.opts.authBaseUrl ||
OAuth2Client.GOOGLE_OAUTH2_AUTH_BASE_URL_;
return rootUrl + '?' + querystring.stringify(opts);
};
/**
* Gets the access token for given code.
* @param {string} code The authorization code.
* @param {function=} opt_callback Optional callback fn.
*/
OAuth2Client.prototype.getToken = function(code, opt_callback) {
var uri = this.opts.tokenUrl || OAuth2Client.GOOGLE_OAUTH2_TOKEN_URL_;
var values = {
code: code,
client_id: this.clientId_,
client_secret: this.clientSecret_,
redirect_uri: this.redirectUri_,
grant_type: 'authorization_code'
};
this.transporter.request({
method: 'POST',
uri: uri,
form: values,
json: true
}, opt_callback);
};
/**
* @private
* Refreshes the access token.
* @param {string} refresh_token Existing refresh token.
* @param {function=} opt_callback Optional callback.
*/
OAuth2Client.prototype.refreshToken_ =
function(refresh_token, opt_callback) {
var uri = this.opts.tokenUrl || OAuth2Client.GOOGLE_OAUTH2_TOKEN_URL_;
var values = {
refresh_token: refresh_token,
client_id: this.clientId_,
client_secret: this.clientSecret_,
grant_type: 'refresh_token'
};
// request for new token
this.transporter.request({
method: 'POST',
uri: uri,
form: values,
json: true
}, opt_callback);
};
/**
* Revokes the access given to token.
* @param {string} token The existing token to be revoked.
* @param {function=} opt_callback Optional callback fn.
*/
OAuth2Client.prototype.revokeToken = function(token, opt_callback) {
this.transporter.request({
uri: OAuth2Client.GOOGLE_OAUTH2_REVOKE_URL_ +
'?' + querystring.stringify({ token: token }),
json: true
}, opt_callback);
};
/**
* Provides a request implementation with OAuth 2.0 flow.
* If credentials have a refresh_token, in cases of HTTP
* 401 and 403 responses, it automatically asks for a new
* access token and replays the unsuccessful request.
* @param {object} opts Request options.
* @param {function=} opt_callback Optional callback.
* @param {boolean=} opt_dontForceRefresh If set, don't ask for a new token
* with refresh_token.
*/
OAuth2Client.prototype.request =
function(opts, opt_callback, opt_dontForceRefresh) {
var that = this;
var credentials = this.credentials;
if (!credentials.access_token && !credentials.refresh_token) {
throw new Error('No access or refresh token is set.');
}
credentials.token_type = credentials.token_type || 'Bearer';
opts.headers = opts.headers || {};
opts.headers['Authorization']
= credentials.token_type + ' ' + credentials.access_token;
this.transporter.request(opts, function(err, body, res) {
var hasAuthError = false;
// TODO(burcud): Should we redo requests without
// an auth error? This question will be invalid when we switch
// to multi part batch requests.
err && err.forEach(function(e) {
hasAuthError = (e.code == 401 || e.code == 403);
});
// if there is an auth error, refresh the token
// and make the request again
if (!opt_dontForceRefresh && hasAuthError && credentials.refresh_token) {
// refresh access token and re-request
that.refreshToken_(credentials.refresh_token, function(err, result) {
if (err) {
opt_callback && opt_callback(err, null, null);
} else {
var tokens = result;
tokens.refresh_token = credentials.refresh_token;
that.credentials = tokens;
that.request(opts, opt_callback, true);
}
});
} else {
opt_callback && opt_callback(err, body, res);
}
});
};
/**
* Export OAuth2Client.
*/
module.exports = OAuth2Client;