1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
7 * OAuth2 API flow implementations.
12 /** @suppress {duplicate} */
13 var remoting
= remoting
|| {};
16 remoting
.OAuth2Api = function() {
20 * @return {string} OAuth2 token URL.
22 remoting
.OAuth2Api
.getOAuth2TokenEndpoint_ = function() {
23 return remoting
.settings
.OAUTH2_BASE_URL
+ '/token';
27 * @return {string} OAuth token revocation URL.
29 remoting
.OAuth2Api
.getOAuth2RevokeTokenEndpoint_ = function() {
30 return remoting
.settings
.OAUTH2_BASE_URL
+ '/revoke';
34 * @return {string} OAuth2 userinfo API URL.
36 remoting
.OAuth2Api
.getOAuth2ApiUserInfoEndpoint_ = function() {
37 return remoting
.settings
.OAUTH2_API_BASE_URL
+ '/v1/userinfo';
42 * Interprets HTTP error responses in authentication XMLHttpRequests.
45 * @param {number} xhrStatus Status (HTTP response code) of the XMLHttpRequest.
46 * @return {remoting.Error} An error code to be raised.
48 remoting
.OAuth2Api
.interpretXhrStatus_
=
50 // Return AUTHENTICATION_FAILED by default, so that the user can try to
51 // recover from an unexpected failure by signing in again.
52 /** @type {remoting.Error} */
53 var error
= remoting
.Error
.AUTHENTICATION_FAILED
;
54 if (xhrStatus
== 400 || xhrStatus
== 401 || xhrStatus
== 403) {
55 error
= remoting
.Error
.AUTHENTICATION_FAILED
;
56 } else if (xhrStatus
== 502 || xhrStatus
== 503) {
57 error
= remoting
.Error
.SERVICE_UNAVAILABLE
;
58 } else if (xhrStatus
== 0) {
59 error
= remoting
.Error
.NETWORK_FAILURE
;
61 console
.warn('Unexpected authentication response code: ' + xhrStatus
);
67 * Asynchronously retrieves a new access token from the server.
69 * @param {function(string, number): void} onDone Callback to invoke when
70 * the access token and expiration time are successfully fetched.
71 * @param {function(remoting.Error):void} onError Callback invoked if an
73 * @param {string} clientId OAuth2 client ID.
74 * @param {string} clientSecret OAuth2 client secret.
75 * @param {string} refreshToken OAuth2 refresh token to be redeemed.
76 * @return {void} Nothing.
78 remoting
.OAuth2Api
.refreshAccessToken = function(
79 onDone
, onError
, clientId
, clientSecret
, refreshToken
) {
80 /** @param {XMLHttpRequest} xhr */
81 var onResponse = function(xhr
) {
82 if (xhr
.status
== 200) {
84 // Don't use jsonParseSafe here unless you move the definition out of
85 // remoting.js, otherwise this won't work from the OAuth trampoline.
86 // TODO(jamiewalch): Fix this once we're no longer using the trampoline.
87 var tokens
= JSON
.parse(xhr
.responseText
);
88 onDone(tokens
['access_token'], tokens
['expires_in']);
90 console
.error('Invalid "token" response from server:',
91 /** @type {*} */ (err
));
92 onError(remoting
.Error
.UNEXPECTED
);
95 console
.error('Failed to refresh token. Status: ' + xhr
.status
+
96 ' response: ' + xhr
.responseText
);
97 onError(remoting
.OAuth2Api
.interpretXhrStatus_(xhr
.status
));
102 'client_id': clientId
,
103 'client_secret': clientSecret
,
104 'refresh_token': refreshToken
,
105 'grant_type': 'refresh_token'
108 remoting
.xhr
.post(remoting
.OAuth2Api
.getOAuth2TokenEndpoint_(),
109 onResponse
, parameters
);
113 * Asynchronously exchanges an authorization code for access and refresh tokens.
115 * @param {function(string, string, number): void} onDone Callback to
116 * invoke when the refresh token, access token and access token expiration
117 * time are successfully fetched.
118 * @param {function(remoting.Error):void} onError Callback invoked if an
120 * @param {string} clientId OAuth2 client ID.
121 * @param {string} clientSecret OAuth2 client secret.
122 * @param {string} code OAuth2 authorization code.
123 * @param {string} redirectUri Redirect URI used to obtain this code.
124 * @return {void} Nothing.
126 remoting
.OAuth2Api
.exchangeCodeForTokens = function(
127 onDone
, onError
, clientId
, clientSecret
, code
, redirectUri
) {
128 /** @param {XMLHttpRequest} xhr */
129 var onResponse = function(xhr
) {
130 if (xhr
.status
== 200) {
132 // Don't use jsonParseSafe here unless you move the definition out of
133 // remoting.js, otherwise this won't work from the OAuth trampoline.
134 // TODO(jamiewalch): Fix this once we're no longer using the trampoline.
135 var tokens
= JSON
.parse(xhr
.responseText
);
136 onDone(tokens
['refresh_token'],
137 tokens
['access_token'], tokens
['expires_in']);
139 console
.error('Invalid "token" response from server:',
140 /** @type {*} */ (err
));
141 onError(remoting
.Error
.UNEXPECTED
);
144 console
.error('Failed to exchange code for token. Status: ' + xhr
.status
+
145 ' response: ' + xhr
.responseText
);
146 onError(remoting
.OAuth2Api
.interpretXhrStatus_(xhr
.status
));
151 'client_id': clientId
,
152 'client_secret': clientSecret
,
153 'redirect_uri': redirectUri
,
155 'grant_type': 'authorization_code'
157 remoting
.xhr
.post(remoting
.OAuth2Api
.getOAuth2TokenEndpoint_(),
158 onResponse
, parameters
);
162 * Get the user's email address.
164 * @param {function(string):void} onDone Callback invoked when the email
165 * address is available.
166 * @param {function(remoting.Error):void} onError Callback invoked if an
168 * @param {string} token Access token.
169 * @return {void} Nothing.
171 remoting
.OAuth2Api
.getEmail = function(onDone
, onError
, token
) {
172 /** @param {XMLHttpRequest} xhr */
173 var onResponse = function(xhr
) {
174 if (xhr
.status
== 200) {
176 var result
= JSON
.parse(xhr
.responseText
);
177 onDone(result
['email']);
179 console
.error('Invalid "userinfo" response from server:',
180 /** @type {*} */ (err
));
181 onError(remoting
.Error
.UNEXPECTED
);
184 console
.error('Failed to get email. Status: ' + xhr
.status
+
185 ' response: ' + xhr
.responseText
);
186 onError(remoting
.OAuth2Api
.interpretXhrStatus_(xhr
.status
));
189 var headers
= { 'Authorization': 'OAuth ' + token
};
190 remoting
.xhr
.get(remoting
.OAuth2Api
.getOAuth2ApiUserInfoEndpoint_(),
191 onResponse
, '', headers
);
195 * Revokes a refresh or an access token.
197 * @param {function():void} onDone Callback invoked when the token is
199 * @param {function(remoting.Error):void} onError Callback invoked if an
201 * @param {string} token An access or refresh token.
202 * @return {void} Nothing.
204 remoting
.OAuth2Api
.revokeToken = function(onDone
, onError
, token
) {
205 /** @param {XMLHttpRequest} xhr */
206 var onResponse = function(xhr
) {
207 if (xhr
.status
== 200) {
210 console
.error('Failed to revoke token. Status: ' + xhr
.status
+
211 ' response: ' + xhr
.responseText
);
212 onError(remoting
.OAuth2Api
.interpretXhrStatus_(xhr
.status
));
216 var parameters
= { 'token': token
};
217 remoting
.xhr
.post(remoting
.OAuth2Api
.getOAuth2RevokeTokenEndpoint_(),
218 onResponse
, parameters
);