|
17 | 17 |
|
18 | 18 | /** |
19 | 19 | * @module purecloud-platform-client-v2/ApiClient |
20 | | - * @version 23.1.0 |
| 20 | + * @version 23.2.0 |
21 | 21 | */ |
22 | 22 |
|
23 | 23 | /** |
|
61 | 61 |
|
62 | 62 | // Expose superagent module for use with superagent-proxy |
63 | 63 | this.superagent = superagent; |
64 | | - |
65 | | - // Check for auth token in hash |
66 | | - this._setValuesFromUrlHash(); |
67 | 64 | }; |
68 | 65 |
|
69 | 66 | /** |
|
98 | 95 | /** |
99 | 96 | * @description Saves the auth token to local storage, if enabled. |
100 | 97 | */ |
101 | | - exports.prototype._saveSettings = function _saveSettings() { |
| 98 | + exports.prototype._saveSettings = function _saveSettings(opts) { |
102 | 99 | try { |
| 100 | + if (!this.authData) this.authData = {}; |
| 101 | + |
| 102 | + if (opts.accessToken) { |
| 103 | + this.authData.accessToken = opts.accessToken; |
| 104 | + this.authentications['PureCloud Auth'].accessToken = opts.accessToken; |
| 105 | + } |
| 106 | + |
| 107 | + if (opts.state) { |
| 108 | + this.authData.state = opts.state; |
| 109 | + } |
| 110 | + |
| 111 | + if (opts.tokenExpiryTime) { |
| 112 | + this.authData.tokenExpiryTime = opts.tokenExpiryTime; |
| 113 | + this.authData.tokenExpiryTimeString = opts.tokenExpiryTimeString; |
| 114 | + } |
| 115 | + |
103 | 116 | // Don't save settings if we aren't supposed to be persisting them |
104 | 117 | if (this.persistSettings !== true) return; |
105 | 118 |
|
|
109 | 122 | return; |
110 | 123 | } |
111 | 124 |
|
112 | | - // Save settings |
113 | | - if (this.authentications['PureCloud Auth'].accessToken) { |
114 | | - localStorage.setItem(`${this.settingsPrefix}_access_token`, this.authentications['PureCloud Auth'].accessToken); |
115 | | - this._debugTrace('Access token saved to local storage'); |
116 | | - } else { |
117 | | - this._debugTrace('Access token cleared'); |
118 | | - localStorage.removeItem(`${this.settingsPrefix}_access_token`); |
119 | | - } |
| 125 | + // Remove state from data so it's not persisted |
| 126 | + let tempData = JSON.parse(JSON.stringify(this.authData)); |
| 127 | + delete tempData.state; |
| 128 | + |
| 129 | + // Save updated auth data |
| 130 | + localStorage.setItem(`${this.settingsPrefix}_auth_data`, JSON.stringify(tempData)); |
| 131 | + this._debugTrace('Auth data saved to local storage'); |
120 | 132 | } catch (e) { |
121 | 133 | console.error(e); |
122 | 134 | } |
|
135 | 147 | return; |
136 | 148 | } |
137 | 149 |
|
138 | | - var token = localStorage.getItem(`${this.settingsPrefix}_access_token`); |
139 | | - if (token) { |
140 | | - this.setAccessToken(token); |
141 | | - this._debugTrace('Access token retrieved from local storage'); |
142 | | - } |
| 150 | + // Load current auth data |
| 151 | + this.authData = localStorage.getItem(`${this.settingsPrefix}_auth_data`); |
| 152 | + if (!this.authData) |
| 153 | + this.authData = {}; |
| 154 | + else |
| 155 | + this.authData = JSON.parse(this.authData); |
| 156 | + if (this.authData.accessToken) this.setAccessToken(this.authData.accessToken); |
143 | 157 | }; |
144 | 158 |
|
145 | 159 | /** |
|
171 | 185 | * @description Initiates the implicit grant login flow. Will attempt to load the token from local storage, if enabled. |
172 | 186 | * @param {string} clientId - The client ID of an OAuth Implicit Grant client |
173 | 187 | * @param {string} redirectUri - The redirect URI of the OAuth Implicit Grant client |
| 188 | + * @param {object} opts - (optional) Additional options |
| 189 | + * @param {string} opts.state - (optional) An arbitrary string to be passed back with the login response. Used for client apps to associate login responses with a request. |
174 | 190 | */ |
175 | | - exports.prototype.loginImplicitGrant = function loginImplicitGrant(clientId, redirectUri) { |
| 191 | + exports.prototype.loginImplicitGrant = function loginImplicitGrant(clientId, redirectUri, opts) { |
176 | 192 | var self = this; |
177 | 193 | this.clientId = clientId; |
178 | 194 | this.redirectUri = redirectUri; |
179 | 195 |
|
| 196 | + // Check for auth token in hash |
| 197 | + this._setValuesFromUrlHash(); |
| 198 | + |
| 199 | + if (!opts) opts = {}; |
| 200 | + |
180 | 201 | return new Promise(function(resolve, reject) { |
181 | 202 | self._testTokenAccess() |
182 | 203 | .then(function() { |
183 | | - resolve(); |
| 204 | + if (!self.authData.state && opts.state) |
| 205 | + self.authData.state = opts.state; |
| 206 | + resolve(self.authData); |
184 | 207 | }) |
185 | 208 | .catch(function(error) { |
| 209 | + self._debugTrace('Error encountered during login. This is normal if the application has not yet been authorized.'); |
| 210 | + self._debugTrace(error); |
186 | 211 | var query = { |
187 | 212 | client_id: encodeURIComponent(self.clientId), |
188 | 213 | redirect_uri: encodeURI(self.redirectUri), |
189 | 214 | response_type: 'token' |
190 | 215 | }; |
| 216 | + if (opts.state) |
| 217 | + query.state = encodeURIComponent(opts.state); |
191 | 218 |
|
192 | 219 | var url = self._buildAuthUrl('oauth/authorize', query); |
193 | 220 | self._debugTrace(`Implicit grant: redirecting to ${url} for authorization...`); |
|
253 | 280 | self.callApi('/api/v2/authorization/permissions', 'GET', |
254 | 281 | null, null, null, null, null, ['PureCloud Auth'], ['application/json'], ['application/json']) |
255 | 282 | .then(function(roles) { |
256 | | - self._saveSettings(); |
257 | 283 | resolve(); |
258 | 284 | }) |
259 | 285 | .catch(function(error) { |
260 | | - self.setAccessToken(); |
| 286 | + self._saveSettings({ accessToken: undefined }); |
261 | 287 | reject(error); |
262 | 288 | }); |
263 | 289 | }); |
|
279 | 305 | return obj; |
280 | 306 | }, {}); |
281 | 307 |
|
282 | | - // Set access token |
283 | | - if(hash.access_token) { |
| 308 | + // Everything goes in here because we only want to act if we found an access token |
| 309 | + if (hash.access_token) { |
| 310 | + let opts = {}; |
| 311 | + |
| 312 | + if (hash.state) { |
| 313 | + /* Auth does some interesting things with encoding. It encodes the data twice, except |
| 314 | + * for spaces, then replaces all spaces with a plus sign. This process must be done |
| 315 | + * in reverse order to properly extract the state data. |
| 316 | + */ |
| 317 | + opts.state = decodeURIComponent(decodeURIComponent(hash.state.replace(/\+/g, '%20'))); |
| 318 | + } |
| 319 | + |
| 320 | + if (hash.expires_in) { |
| 321 | + opts.tokenExpiryTime = (new Date()).getTime() + (parseInt(decodeURIComponent(decodeURIComponent(hash.expires_in.replace(/\+/g, '%20')))) * 1000); |
| 322 | + opts.tokenExpiryTimeString = (new Date(opts.tokenExpiryTime)).toUTCString(); |
| 323 | + } |
284 | 324 | // Set access token |
285 | | - this.setAccessToken(hash.access_token); |
| 325 | + opts.accessToken = decodeURIComponent(decodeURIComponent(hash.access_token.replace(/\+/g, '%20'))); |
286 | 326 |
|
287 | 327 | // Remove hash from URL |
288 | 328 | // Credit: https://stackoverflow.com/questions/1397329/how-to-remove-the-hash-from-window-location-with-javascript-without-page-refresh/5298684#5298684 |
|
301 | 341 | document.body.scrollTop = scrollV; |
302 | 342 | document.body.scrollLeft = scrollH; |
303 | 343 | } |
| 344 | + |
| 345 | + this._saveSettings(opts); |
304 | 346 | } |
305 | 347 | }; |
306 | 348 |
|
|
309 | 351 | * @param {string} token - The access token |
310 | 352 | */ |
311 | 353 | exports.prototype.setAccessToken = function(token) { |
312 | | - // Set token for API use |
313 | | - this.authentications['PureCloud Auth'].accessToken = token; |
314 | | - |
315 | | - this._saveSettings(); |
| 354 | + this._saveSettings({ accessToken: token }); |
316 | 355 | }; |
317 | 356 |
|
318 | 357 | /** |
|
345 | 384 | */ |
346 | 385 | exports.prototype.logout = function() { |
347 | 386 | if(exports.hasLocalStorage) { |
348 | | - this.setAccessToken(); |
| 387 | + this._saveSettings({ |
| 388 | + accessToken: undefined, |
| 389 | + state: undefined, |
| 390 | + tokenExpiryTime: undefined, |
| 391 | + tokenExpiryTimeString: undefined |
| 392 | + }); |
349 | 393 | } |
350 | 394 |
|
351 | 395 | var query = { |
|
650 | 694 |
|
651 | 695 | // set header parameters |
652 | 696 | request.set(this.defaultHeaders).set(this.normalizeParams(headerParams)); |
653 | | - //request.set({ 'purecloud-sdk': '23.1.0' }); |
| 697 | + //request.set({ 'purecloud-sdk': '23.2.0' }); |
654 | 698 |
|
655 | 699 | // set request timeout |
656 | 700 | request.timeout(this.timeout); |
|
0 commit comments