Index: remoting/webapp/oauth2.js |
diff --git a/remoting/webapp/oauth2.js b/remoting/webapp/oauth2.js |
index a6c2452c5810c067b9f763692f0345bf1793be2f..e2dc9334cbf5c4b3e91472495e2691a724d65a56 100644 |
--- a/remoting/webapp/oauth2.js |
+++ b/remoting/webapp/oauth2.js |
@@ -28,6 +28,9 @@ remoting.OAuth2 = function() { |
/** @private */ |
remoting.OAuth2.prototype.KEY_REFRESH_TOKEN_ = 'oauth2-refresh-token'; |
/** @private */ |
+remoting.OAuth2.prototype.KEY_REFRESH_TOKEN_REVOKABLE_ = |
+ 'oauth2-refresh-token-revokable'; |
+/** @private */ |
remoting.OAuth2.prototype.KEY_ACCESS_TOKEN_ = 'oauth2-access-token'; |
/** @private */ |
remoting.OAuth2.prototype.KEY_EMAIL_ = 'remoting-email'; |
@@ -41,10 +44,12 @@ remoting.OAuth2.prototype.SCOPE_ = |
/** @private */ |
remoting.OAuth2.prototype.OAUTH2_TOKEN_ENDPOINT_ = |
'https://accounts.google.com/o/oauth2/token'; |
- |
+/** @private */ |
+remoting.OAuth2.prototype.OAUTH2_REVOKE_TOKEN_ENDPOINT_ = |
+ 'https://accounts.google.com/o/oauth2/revoke'; |
/** @return {boolean} True if the app is already authenticated. */ |
remoting.OAuth2.prototype.isAuthenticated = function() { |
- if (this.getRefreshToken()) { |
+ if (this.getRefreshToken_()) { |
return true; |
} |
return false; |
@@ -56,22 +61,46 @@ remoting.OAuth2.prototype.isAuthenticated = function() { |
* @return {void} Nothing. |
*/ |
remoting.OAuth2.prototype.clear = function() { |
- window.localStorage.removeItem(this.KEY_REFRESH_TOKEN_); |
window.localStorage.removeItem(this.KEY_EMAIL_); |
this.clearAccessToken(); |
+ this.clearRefreshToken_(); |
}; |
/** |
+ * Sets the refresh token. |
+ * |
+ * This method also marks the token as revokable, so that this object will |
+ * revoke the token when it no longer needs it. |
+ * |
* @param {string} token The new refresh token. |
* @return {void} Nothing. |
*/ |
remoting.OAuth2.prototype.setRefreshToken = function(token) { |
window.localStorage.setItem(this.KEY_REFRESH_TOKEN_, escape(token)); |
+ window.localStorage.setItem(this.KEY_REFRESH_TOKEN_REVOKABLE_, true); |
this.clearAccessToken(); |
}; |
-/** @return {?string} The refresh token, if authenticated, or NULL. */ |
-remoting.OAuth2.prototype.getRefreshToken = function() { |
+/** |
+ * Gets the refresh token. |
+ * |
+ * This method also marks the refresh token as not revokable, so that this |
+ * object will not revoke the token when it no longer needs it. After this |
+ * object has exported the token, it cannot know whether it is still in use |
+ * when this object no longer needs it. |
+ * |
+ * @return {?string} The refresh token, if authenticated, or NULL. |
+ */ |
+remoting.OAuth2.prototype.exportRefreshToken = function() { |
+ window.localStorage.removeItem(this.KEY_REFRESH_TOKEN_REVOKABLE_); |
+ return this.getRefreshToken_(); |
+}; |
+ |
+/** |
+ * @return {?string} The refresh token, if authenticated, or NULL. |
+ * @private |
+ */ |
+remoting.OAuth2.prototype.getRefreshToken_ = function() { |
var value = window.localStorage.getItem(this.KEY_REFRESH_TOKEN_); |
if (typeof value == 'string') { |
return unescape(value); |
@@ -80,6 +109,20 @@ remoting.OAuth2.prototype.getRefreshToken = function() { |
}; |
/** |
+ * Clears the refresh token. |
+ * |
+ * @return {void} Nothing. |
+ * @private |
+ */ |
+remoting.OAuth2.prototype.clearRefreshToken_ = function() { |
+ if (window.localStorage.getItem(this.KEY_REFRESH_TOKEN_REVOKABLE_)) { |
+ this.revokeToken_(this.getRefreshToken_()); |
+ } |
+ window.localStorage.removeItem(this.KEY_REFRESH_TOKEN_); |
+ window.localStorage.removeItem(this.KEY_REFRESH_TOKEN_REVOKABLE_); |
+}; |
+ |
+/** |
* @param {string} token The new access token. |
* @param {number} expiration Expiration time in milliseconds since epoch. |
* @return {void} Nothing. |
@@ -200,7 +243,7 @@ remoting.OAuth2.prototype.refreshAccessToken = function(onDone) { |
var parameters = { |
'client_id': this.CLIENT_ID_, |
'client_secret': this.CLIENT_SECRET_, |
- 'refresh_token': this.getRefreshToken(), |
+ 'refresh_token': this.getRefreshToken_(), |
'grant_type': 'refresh_token' |
}; |
@@ -264,6 +307,31 @@ remoting.OAuth2.prototype.exchangeCodeForToken = function(code, onDone) { |
}; |
/** |
+ * Revokes a refresh or an access token. |
+ * |
+ * @param {string?} token An access or refresh token. |
+ * @return {void} Nothing. |
+ * @private |
+ */ |
+remoting.OAuth2.prototype.revokeToken_ = function(token) { |
+ if (!token || (token.length == 0)) { |
+ return; |
+ } |
+ var parameters = { 'token': token }; |
+ |
+ /** @param {XMLHttpRequest} xhr The XHR reply. */ |
+ var processResponse = function(xhr) { |
+ if (xhr.status != 200) { |
+ console.log('Failed to revoke token. Status: ' + xhr.status + |
+ ' ; response: ' + xhr.responseText + ' ; xhr: ', xhr); |
+ } |
+ }; |
+ remoting.xhr.post(this.OAUTH2_REVOKE_TOKEN_ENDPOINT_, |
+ processResponse, |
+ parameters); |
+}; |
+ |
+/** |
* Call myfunc with an access token as the only parameter. |
* |
* This will refresh the access token if necessary. If the access token |