ducky/web
2015-07-07
Parent:3bdc03963abe
ducky/web/src/helpers/oauth-refresh.js
Fix bug in oauth-refresh, update for hosted path. Our nginx-fronted path has changed, so update the helper to hit the right URL. Also, fix a bug that would cause every failed request to be retried, which was suboptimal.
| paddy@11 | 1 import app from 'ampersand-app' |
| paddy@11 | 2 import xhr from 'xhr' |
| paddy@11 | 3 import qs from 'qs' |
| paddy@11 | 4 import Sync from 'ampersand-sync' |
| paddy@11 | 5 import config from '../config' |
| paddy@11 | 6 |
| paddy@11 | 7 const getRefresh = (opts, callback) => { |
| paddy@11 | 8 const refreshOpts = { |
| paddy@18 | 9 url: config.urlBase + '/auth/token', |
| paddy@11 | 10 method: 'POST', |
| paddy@11 | 11 headers: { |
| paddy@11 | 12 'Content-Type': 'application/x-www-form-urlencoded', |
| paddy@11 | 13 'Authorization': 'Basic ' + btoa(config.clientID + ':' + config.clientSecret), |
| paddy@11 | 14 }, |
| paddy@11 | 15 data: qs.stringify({ |
| paddy@11 | 16 'grant_type': 'refresh_token', |
| paddy@11 | 17 'refresh_token': app.me.refresh_token |
| paddy@11 | 18 }), |
| paddy@11 | 19 } |
| paddy@11 | 20 xhr(refreshOpts, function(err, resp, body) { |
| paddy@11 | 21 if (resp.statusCode != 200) { |
| paddy@11 | 22 callback(err, resp, body) |
| paddy@11 | 23 return |
| paddy@11 | 24 } |
| paddy@11 | 25 if (body && resp.headers['content-type'] == 'application/json') { |
| paddy@11 | 26 try { |
| paddy@11 | 27 body = JSON.parse(body) |
| paddy@11 | 28 } catch (err) { |
| paddy@11 | 29 app.trigger('token:refreshError', body) |
| paddy@11 | 30 callback(err, resp, body) |
| paddy@11 | 31 } |
| paddy@11 | 32 } |
| paddy@11 | 33 if (body.access_token) { |
| paddy@11 | 34 app.me.set(body) |
| paddy@11 | 35 } else { |
| paddy@11 | 36 app.trigger('token:refreshError', body) |
| paddy@11 | 37 } |
| paddy@11 | 38 callback(err, resp, body) |
| paddy@11 | 39 }) |
| paddy@11 | 40 } |
| paddy@11 | 41 |
| paddy@11 | 42 const shouldRefreshXHR = (err, resp, body) => { |
| paddy@11 | 43 if(body && resp.headers['Content-Type'] == 'application/json') { |
| paddy@11 | 44 try { |
| paddy@11 | 45 body = JSON.parse(body) |
| paddy@11 | 46 } catch (err) { |
| paddy@11 | 47 return false |
| paddy@11 | 48 } |
| paddy@11 | 49 } |
| paddy@11 | 50 if (resp.statusCode == 401 && body.errors && body.errors[0] |
| paddy@11 | 51 && body.errors[0].header == 'authorization' && body.errors[0].error == 'access_denied') { |
| paddy@11 | 52 return true |
| paddy@11 | 53 } |
| paddy@11 | 54 return false |
| paddy@11 | 55 } |
| paddy@11 | 56 |
| paddy@11 | 57 const doRefreshXHR = (opts, callback) => { |
| paddy@11 | 58 opts.noRefresh = true |
| paddy@11 | 59 getRefresh(opts, function(err, resp, body) { |
| paddy@11 | 60 if (body.access_token) { |
| paddy@11 | 61 opts.headers['Authorization'] = 'Bearer '+body.access_token |
| paddy@11 | 62 xhr(opts, callback) |
| paddy@11 | 63 } |
| paddy@11 | 64 }) |
| paddy@11 | 65 } |
| paddy@11 | 66 |
| paddy@11 | 67 const refreshXHR = (opts, callback) => { |
| paddy@11 | 68 return xhr(opts, function(err, resp, body) { |
| paddy@11 | 69 if (opts.noRefresh || !shouldRefreshXHR(err, resp, body)) { |
| paddy@11 | 70 callback(err, resp, body) |
| paddy@11 | 71 return |
| paddy@11 | 72 } |
| paddy@11 | 73 doRefreshXHR(opts, callback) |
| paddy@11 | 74 }) |
| paddy@11 | 75 xhr(opts, callback) |
| paddy@11 | 76 } |
| paddy@11 | 77 |
| paddy@11 | 78 const shouldRefreshSync = (resp) => { |
| paddy@11 | 79 if (resp && resp.errors && resp.errors[0] |
| paddy@11 | 80 && resp.errors[0].header == 'authorization' && resp.errors[0].error == 'access_denied') { |
| paddy@11 | 81 return true |
| paddy@11 | 82 } |
| paddy@11 | 83 return false |
| paddy@11 | 84 } |
| paddy@11 | 85 |
| paddy@11 | 86 const doRefreshSync = (action, moc, opts) => { |
| paddy@11 | 87 opts.noRefresh = true |
| paddy@11 | 88 getRefresh(opts, function(err, resp, body) { |
| paddy@11 | 89 if (body.access_token) { |
| paddy@11 | 90 Sync(action, moc, opts) |
| paddy@11 | 91 } |
| paddy@11 | 92 }) |
| paddy@11 | 93 } |
| paddy@11 | 94 |
| paddy@11 | 95 const refreshSync = (action, moc, opts) => { |
| paddy@11 | 96 const oldError = opts.error |
| paddy@11 | 97 opts.error = function(resp) { |
| paddy@18 | 98 if(opts.noRefresh || !shouldRefreshSync(resp)) { |
| paddy@11 | 99 oldError(resp) |
| paddy@11 | 100 return |
| paddy@11 | 101 } |
| paddy@11 | 102 doRefreshSync(action, moc, opts) |
| paddy@11 | 103 } |
| paddy@11 | 104 Sync(action, moc, opts) |
| paddy@11 | 105 } |
| paddy@11 | 106 |
| paddy@11 | 107 const refresh = { |
| paddy@11 | 108 Sync: refreshSync, |
| paddy@11 | 109 XHR: refreshXHR, |
| paddy@11 | 110 } |
| paddy@11 | 111 |
| paddy@11 | 112 export default refresh |