- add sources.
[platform/framework/web/crosswalk.git] / src / remoting / webapp / oauth2_api.js
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.
4
5 /**
6  * @fileoverview
7  * OAuth2 API flow implementations.
8  */
9
10 'use strict';
11
12 /** @suppress {duplicate} */
13 var remoting = remoting || {};
14
15 /** @constructor */
16 remoting.OAuth2Api = function() {
17 };
18
19 /** @private
20  *  @return {string} OAuth2 token URL.
21  */
22 remoting.OAuth2Api.getOAuth2TokenEndpoint_ = function() {
23   return remoting.settings.OAUTH2_BASE_URL + '/token';
24 };
25
26 /** @private
27  *  @return {string} OAuth token revocation URL.
28  */
29 remoting.OAuth2Api.getOAuth2RevokeTokenEndpoint_ = function() {
30   return remoting.settings.OAUTH2_BASE_URL + '/revoke';
31 };
32
33 /** @private
34  *  @return {string} OAuth2 userinfo API URL.
35  */
36 remoting.OAuth2Api.getOAuth2ApiUserInfoEndpoint_ = function() {
37   return remoting.settings.OAUTH2_API_BASE_URL + '/v1/userinfo';
38 };
39
40
41 /**
42  * Interprets HTTP error responses in authentication XMLHttpRequests.
43  *
44  * @private
45  * @param {number} xhrStatus Status (HTTP response code) of the XMLHttpRequest.
46  * @return {remoting.Error} An error code to be raised.
47  */
48 remoting.OAuth2Api.interpretXhrStatus_ =
49     function(xhrStatus) {
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;
60   } else {
61     console.warn('Unexpected authentication response code: ' + xhrStatus);
62   }
63   return error;
64 };
65
66 /**
67  * Asynchronously retrieves a new access token from the server.
68  *
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
72  *     error occurs.
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.
77  */
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) {
83       try {
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']);
89       } catch (err) {
90         console.error('Invalid "token" response from server:',
91                       /** @type {*} */ (err));
92         onError(remoting.Error.UNEXPECTED);
93       }
94     } else {
95       console.error('Failed to refresh token. Status: ' + xhr.status +
96                     ' response: ' + xhr.responseText);
97       onError(remoting.OAuth2Api.interpretXhrStatus_(xhr.status));
98     }
99   };
100
101   var parameters = {
102     'client_id': clientId,
103     'client_secret': clientSecret,
104     'refresh_token': refreshToken,
105     'grant_type': 'refresh_token'
106   };
107
108   remoting.xhr.post(remoting.OAuth2Api.getOAuth2TokenEndpoint_(),
109                     onResponse, parameters);
110 };
111
112 /**
113  * Asynchronously exchanges an authorization code for access and refresh tokens.
114  *
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
119  *     error occurs.
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.
125  */
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) {
131       try {
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']);
138       } catch (err) {
139         console.error('Invalid "token" response from server:',
140                       /** @type {*} */ (err));
141         onError(remoting.Error.UNEXPECTED);
142       }
143     } else {
144       console.error('Failed to exchange code for token. Status: ' + xhr.status +
145                     ' response: ' + xhr.responseText);
146       onError(remoting.OAuth2Api.interpretXhrStatus_(xhr.status));
147     }
148   };
149
150   var parameters = {
151     'client_id': clientId,
152     'client_secret': clientSecret,
153     'redirect_uri': redirectUri,
154     'code': code,
155     'grant_type': 'authorization_code'
156   };
157   remoting.xhr.post(remoting.OAuth2Api.getOAuth2TokenEndpoint_(),
158                     onResponse, parameters);
159 };
160
161 /**
162  * Get the user's email address.
163  *
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
167  *     error occurs.
168  * @param {string} token Access token.
169  * @return {void} Nothing.
170  */
171 remoting.OAuth2Api.getEmail = function(onDone, onError, token) {
172   /** @param {XMLHttpRequest} xhr */
173   var onResponse = function(xhr) {
174     if (xhr.status == 200) {
175       try {
176         var result = JSON.parse(xhr.responseText);
177         onDone(result['email']);
178       } catch (err) {
179         console.error('Invalid "userinfo" response from server:',
180                       /** @type {*} */ (err));
181         onError(remoting.Error.UNEXPECTED);
182       }
183     } else {
184       console.error('Failed to get email. Status: ' + xhr.status +
185                     ' response: ' + xhr.responseText);
186       onError(remoting.OAuth2Api.interpretXhrStatus_(xhr.status));
187     }
188   };
189   var headers = { 'Authorization': 'OAuth ' + token };
190   remoting.xhr.get(remoting.OAuth2Api.getOAuth2ApiUserInfoEndpoint_(),
191                    onResponse, '', headers);
192 };
193
194 /**
195  * Revokes a refresh or an access token.
196  *
197  * @param {function():void} onDone Callback invoked when the token is
198  *     revoked.
199  * @param {function(remoting.Error):void} onError Callback invoked if an
200  *     error occurs.
201  * @param {string} token An access or refresh token.
202  * @return {void} Nothing.
203  */
204 remoting.OAuth2Api.revokeToken = function(onDone, onError, token) {
205   /** @param {XMLHttpRequest} xhr */
206   var onResponse = function(xhr) {
207     if (xhr.status == 200) {
208       onDone();
209     } else {
210       console.error('Failed to revoke token. Status: ' + xhr.status +
211                     ' response: ' + xhr.responseText);
212       onError(remoting.OAuth2Api.interpretXhrStatus_(xhr.status));
213     }
214   };
215
216   var parameters = { 'token': token };
217   remoting.xhr.post(remoting.OAuth2Api.getOAuth2RevokeTokenEndpoint_(),
218                     onResponse, parameters);
219 };