| 
									
										
										
										
											2017-02-08 00:48:07 -05:00
										 |  |  | ;(function (exports) { | 
					
						
							| 
									
										
										
										
											2017-01-17 22:29:46 -05:00
										 |  |  |   'use strict'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // NOTE: we assume that directive.provider_uri exists
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   var core = {}; | 
					
						
							| 
									
										
										
										
											2017-02-08 04:18:15 -05:00
										 |  |  |   core.urls = core; | 
					
						
							| 
									
										
										
										
											2017-01-17 22:29:46 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-31 19:12:31 -07:00
										 |  |  |   function getDefaultAppApiBase() { | 
					
						
							|  |  |  |     console.warn('[deprecated] using window.location.host when opts.appApiBase should be used'); | 
					
						
							|  |  |  |     return 'https://' + window.location.host; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-10 21:34:00 -05:00
										 |  |  |   core.parsescope = function (scope) { | 
					
						
							|  |  |  |     return (scope||'').split(/[+, ]/g); | 
					
						
							|  |  |  |   }; | 
					
						
							| 
									
										
										
										
											2017-01-17 22:29:46 -05:00
										 |  |  |   core.stringifyscope = function (scope) { | 
					
						
							|  |  |  |     if (Array.isArray(scope)) { | 
					
						
							|  |  |  |       scope = scope.join(' '); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return scope; | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   core.querystringify = function (params) { | 
					
						
							|  |  |  |     var qs = []; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Object.keys(params).forEach(function (key) { | 
					
						
							| 
									
										
										
										
											2017-01-18 16:24:30 -05:00
										 |  |  |       // TODO nullify instead?
 | 
					
						
							|  |  |  |       if ('undefined' === typeof params[key]) { | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-17 22:29:46 -05:00
										 |  |  |       if ('scope' === key) { | 
					
						
							|  |  |  |         params[key] = core.stringifyscope(params[key]); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2017-01-18 16:24:30 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-17 22:29:46 -05:00
										 |  |  |       qs.push(encodeURIComponent(key) + '=' + encodeURIComponent(params[key])); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return qs.join('&'); | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-23 12:51:34 -07:00
										 |  |  |   // Modified from http://stackoverflow.com/a/7826782
 | 
					
						
							|  |  |  |   core.queryparse = function (search) { | 
					
						
							| 
									
										
										
										
											2017-01-24 13:10:16 -07:00
										 |  |  |     // parse a query or a hash
 | 
					
						
							|  |  |  |     if (-1 !== ['#', '?'].indexOf(search[0])) { | 
					
						
							|  |  |  |       search = search.substring(1); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-02-06 14:41:25 -07:00
										 |  |  |     // Solve for case of search within hash
 | 
					
						
							|  |  |  |     // example: #/authorization_dialog/?state=...&redirect_uri=...
 | 
					
						
							|  |  |  |     var queryIndex = search.indexOf('?'); | 
					
						
							|  |  |  |     if (-1 !== queryIndex) { | 
					
						
							|  |  |  |       search = search.substr(queryIndex + 1); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-01-23 12:51:34 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     var args = search.split('&'); | 
					
						
							|  |  |  |     var argsParsed = {}; | 
					
						
							|  |  |  |     var i, arg, kvp, key, value; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (i = 0; i < args.length; i += 1) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         arg = args[i]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (-1 === arg.indexOf('=')) { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-24 13:10:16 -07:00
										 |  |  |           argsParsed[decodeURIComponent(arg).trim()] = true; | 
					
						
							| 
									
										
										
										
											2017-01-23 12:51:34 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-24 13:10:16 -07:00
										 |  |  |           kvp = arg.split('='); | 
					
						
							|  |  |  |           key = decodeURIComponent(kvp[0]).trim(); | 
					
						
							|  |  |  |           value = decodeURIComponent(kvp[1]).trim(); | 
					
						
							|  |  |  |           argsParsed[key] = value; | 
					
						
							| 
									
										
										
										
											2017-01-23 12:51:34 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return argsParsed; | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-08 00:48:07 -05:00
										 |  |  |   core.formatError = function (providerUri, params) { | 
					
						
							| 
									
										
										
										
											2017-02-08 04:18:15 -05:00
										 |  |  |     var err = new Error(params.error_description || params.error.message || "Unknown error when discoving provider '" + providerUri + "'"); | 
					
						
							|  |  |  |     err.uri = params.error_uri || params.error.uri; | 
					
						
							|  |  |  |     err.code = params.error.code || params.error; | 
					
						
							| 
									
										
										
										
											2017-02-08 00:48:07 -05:00
										 |  |  |     return err; | 
					
						
							|  |  |  |   }; | 
					
						
							| 
									
										
										
										
											2017-02-09 21:51:22 -05:00
										 |  |  |   core.normalizePath = function (path) { | 
					
						
							|  |  |  |     return path.replace(/^\//, '').replace(/\/$/, ''); | 
					
						
							|  |  |  |   }; | 
					
						
							| 
									
										
										
										
											2017-02-08 00:48:07 -05:00
										 |  |  |   core.normalizeUri = function (providerUri) { | 
					
						
							|  |  |  |     // tested with
 | 
					
						
							|  |  |  |     //   example.com
 | 
					
						
							|  |  |  |     //   example.com/
 | 
					
						
							|  |  |  |     //   http://example.com
 | 
					
						
							|  |  |  |     //   https://example.com/
 | 
					
						
							|  |  |  |     return providerUri | 
					
						
							|  |  |  |       .replace(/^(https?:\/\/)?/i, '') | 
					
						
							|  |  |  |       .replace(/\/?$/, '') | 
					
						
							|  |  |  |       ; | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  |   core.normalizeUrl = function (providerUri) { | 
					
						
							|  |  |  |     // tested with
 | 
					
						
							|  |  |  |     //   example.com
 | 
					
						
							|  |  |  |     //   example.com/
 | 
					
						
							|  |  |  |     //   http://example.com
 | 
					
						
							|  |  |  |     //   https://example.com/
 | 
					
						
							|  |  |  |     return providerUri | 
					
						
							|  |  |  |       .replace(/^(https?:\/\/)?/i, 'https://') | 
					
						
							|  |  |  |       .replace(/\/?$/, '') | 
					
						
							|  |  |  |       ; | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-24 13:16:21 -07:00
										 |  |  |   // these might not really belong in core... not sure
 | 
					
						
							|  |  |  |   // there should be node.js- and browser-specific versions probably
 | 
					
						
							| 
									
										
										
										
											2017-01-24 13:10:16 -07:00
										 |  |  |   core.utils = { | 
					
						
							|  |  |  |     urlSafeBase64ToBase64: function (b64) { | 
					
						
							|  |  |  |       // URL-safe Base64 to Base64
 | 
					
						
							| 
									
										
										
										
											2017-02-07 18:31:05 -05:00
										 |  |  |       // https://en.wikipedia.org/wiki/Base64
 | 
					
						
							|  |  |  |       // https://gist.github.com/catwell/3046205
 | 
					
						
							|  |  |  |       var mod = b64.length % 4; | 
					
						
							|  |  |  |       if (2 === mod) { b64 += '=='; } | 
					
						
							|  |  |  |       if (3 === mod) { b64 += '='; } | 
					
						
							| 
									
										
										
										
											2017-01-24 13:10:16 -07:00
										 |  |  |       b64 = b64.replace(/-/g, '+').replace(/_/g, '/'); | 
					
						
							|  |  |  |       return b64; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   , base64ToUrlSafeBase64: function (b64) { | 
					
						
							|  |  |  |       // Base64 to URL-safe Base64
 | 
					
						
							|  |  |  |       b64 = b64.replace(/\+/g, '-').replace(/\//g, '_'); | 
					
						
							|  |  |  |       b64 = b64.replace(/=+/g, ''); | 
					
						
							|  |  |  |       return b64; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-02-06 13:26:46 -07:00
										 |  |  |   , randomState: function () { | 
					
						
							|  |  |  |       var i; | 
					
						
							|  |  |  |       var ch; | 
					
						
							|  |  |  |       var str; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // TODO put in different file for browser vs node
 | 
					
						
							|  |  |  |       try { | 
					
						
							|  |  |  |         return Array.prototype.slice.call(window.crypto.getRandomValues(new Uint8Array(16))).map(function (ch) { return (ch).toString(16); }).join(''); | 
					
						
							|  |  |  |       } catch(e) { | 
					
						
							|  |  |  |         // TODO use fisher-yates on 0..255 and select [0] 16 times
 | 
					
						
							|  |  |  |         // [security] https://medium.com/@betable/tifu-by-using-math-random-f1c308c4fd9d#.5qx0bf95a
 | 
					
						
							|  |  |  |         // https://github.com/v8/v8/blob/b0e4dce6091a8777bda80d962df76525dc6c5ea9/src/js/math.js#L135-L144
 | 
					
						
							|  |  |  |         // Note: newer versions of v8 do not have this bug, but other engines may still
 | 
					
						
							|  |  |  |         console.warn('[security] crypto.getRandomValues() failed, falling back to Math.random()'); | 
					
						
							|  |  |  |         str = ''; | 
					
						
							|  |  |  |         for (i = 0; i < 32; i += 1) { | 
					
						
							|  |  |  |           ch = Math.round(Math.random() * 255).toString(16); | 
					
						
							|  |  |  |           if (ch.length < 2) { ch = '0' + ch; } | 
					
						
							|  |  |  |           str += ch; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return str; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-01-24 13:10:16 -07:00
										 |  |  |   }; | 
					
						
							|  |  |  |   core.jwt = { | 
					
						
							|  |  |  |     // decode only (no verification)
 | 
					
						
							|  |  |  |     decode: function (str) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // 'abc.qrs.xyz'
 | 
					
						
							|  |  |  |       // [ 'abc', 'qrs', 'xyz' ]
 | 
					
						
							|  |  |  |       // [ {}, {}, 'foo' ]
 | 
					
						
							|  |  |  |       // { header: {}, payload: {}, signature: }
 | 
					
						
							|  |  |  |       var parts = str.split(/\./g); | 
					
						
							| 
									
										
										
										
											2017-02-07 18:31:05 -05:00
										 |  |  |       var jsons = parts.slice(0, 2).map(function (urlsafe64) { | 
					
						
							| 
									
										
										
										
											2017-01-24 13:10:16 -07:00
										 |  |  |         var atob = exports.atob || require('atob'); | 
					
						
							| 
									
										
										
										
											2017-02-07 18:31:05 -05:00
										 |  |  |         var b64 = core.utils.urlSafeBase64ToBase64(urlsafe64); | 
					
						
							|  |  |  |         return atob(b64); | 
					
						
							| 
									
										
										
										
											2017-01-24 13:10:16 -07:00
										 |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       return { | 
					
						
							|  |  |  |         header: JSON.parse(jsons[0]) | 
					
						
							|  |  |  |       , payload: JSON.parse(jsons[1]) | 
					
						
							| 
									
										
										
										
											2017-01-24 13:16:21 -07:00
										 |  |  |       , signature: parts[2] // should remain url-safe base64
 | 
					
						
							| 
									
										
										
										
											2017-01-24 13:10:16 -07:00
										 |  |  |       }; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-02-13 12:46:12 -05:00
										 |  |  |   , getFreshness: function (tokenMeta, staletime, now) { | 
					
						
							| 
									
										
										
										
											2017-02-08 04:18:15 -05:00
										 |  |  |       staletime = staletime || (15 * 60); | 
					
						
							|  |  |  |       now = now || Date.now(); | 
					
						
							| 
									
										
										
										
											2017-02-13 12:46:12 -05:00
										 |  |  |       var fresh = ((parseInt(tokenMeta.exp, 10) || 0) - Math.round(now / 1000)); | 
					
						
							| 
									
										
										
										
											2017-02-08 04:18:15 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |       if (fresh >= staletime) { | 
					
						
							|  |  |  |         return 'fresh'; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (fresh <= 0) { | 
					
						
							|  |  |  |         return 'expired'; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       return 'stale'; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-01-24 13:10:16 -07:00
										 |  |  |     // encode-only (no signature)
 | 
					
						
							|  |  |  |   , encode: function (parts) { | 
					
						
							|  |  |  |       parts.header = parts.header || { alg: 'none', typ: 'jwt' }; | 
					
						
							|  |  |  |       parts.signature = parts.signature || ''; | 
					
						
							| 
									
										
										
										
											2017-01-24 13:16:21 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |       var btoa = exports.btoa || require('btoa'); | 
					
						
							| 
									
										
										
										
											2017-01-24 13:10:16 -07:00
										 |  |  |       var result = [ | 
					
						
							| 
									
										
										
										
											2017-01-24 13:16:21 -07:00
										 |  |  |         core.utils.base64ToUrlSafeBase64(btoa(JSON.stringify(parts.header, null))) | 
					
						
							|  |  |  |       , core.utils.base64ToUrlSafeBase64(btoa(JSON.stringify(parts.payload, null))) | 
					
						
							|  |  |  |       , parts.signature // should already be url-safe base64
 | 
					
						
							| 
									
										
										
										
											2017-01-24 13:10:16 -07:00
										 |  |  |       ].join('.'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       return result; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-09 21:51:22 -05:00
										 |  |  |   core.urls.discover = function (providerUri, opts) { | 
					
						
							|  |  |  |     if (!providerUri) { | 
					
						
							|  |  |  |       throw new Error("cannot discover without providerUri"); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-02-10 20:23:57 -07:00
										 |  |  |     if (!opts.client_id) { | 
					
						
							|  |  |  |       throw new Error("cannot discover without options.client_id"); | 
					
						
							| 
									
										
										
										
											2017-02-09 21:51:22 -05:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-02-10 23:45:34 -05:00
										 |  |  |     var clientId = core.normalizeUrl(opts.client_id || opts.client_uri); | 
					
						
							|  |  |  |     providerUri = core.normalizeUrl(providerUri); | 
					
						
							| 
									
										
										
										
											2017-02-09 21:51:22 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     var params = { | 
					
						
							|  |  |  |       action: 'directives' | 
					
						
							|  |  |  |     , state: core.utils.randomState() | 
					
						
							| 
									
										
										
										
											2017-02-10 23:45:34 -05:00
										 |  |  |     , redirect_uri: clientId + (opts.client_callback_path || '/.well-known/oauth3/callback.html') | 
					
						
							| 
									
										
										
										
											2017-02-09 21:51:22 -05:00
										 |  |  |     , response_type: 'rpc' | 
					
						
							|  |  |  |     , _method: 'GET' | 
					
						
							|  |  |  |     , _pathname: '.well-known/oauth3/directives.json' | 
					
						
							|  |  |  |     , debug: opts.debug || undefined | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     var result = { | 
					
						
							|  |  |  |       url: providerUri + '/.well-known/oauth3/#/?' + core.querystringify(params) | 
					
						
							|  |  |  |     , state: params.state | 
					
						
							|  |  |  |     , method: 'GET' | 
					
						
							|  |  |  |     , query: params | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return result; | 
					
						
							|  |  |  |   }; | 
					
						
							| 
									
										
										
										
											2017-02-08 04:18:15 -05:00
										 |  |  |   core.urls.authorizationCode = function (/*directive, scope, redirectUri, clientId*/) { | 
					
						
							| 
									
										
										
										
											2017-01-17 22:29:46 -05:00
										 |  |  |     //
 | 
					
						
							|  |  |  |     // Example Authorization Code Request
 | 
					
						
							|  |  |  |     // (not for use in the browser)
 | 
					
						
							|  |  |  |     //
 | 
					
						
							|  |  |  |     // GET https://example.com/api/org.oauth3.provider/authorization_dialog
 | 
					
						
							|  |  |  |     //  ?response_type=code
 | 
					
						
							|  |  |  |     //  &scope=`encodeURIComponent('profile.login profile.email')`
 | 
					
						
							| 
									
										
										
										
											2017-02-06 13:26:46 -07:00
										 |  |  |     //  &state=`cryptoutil.random().toString('hex')`
 | 
					
						
							| 
									
										
										
										
											2017-01-17 22:29:46 -05:00
										 |  |  |     //  &client_id=xxxxxxxxxxx
 | 
					
						
							|  |  |  |     //  &redirect_uri=`encodeURIComponent('https://myapp.com/oauth3.html')`
 | 
					
						
							|  |  |  |     //
 | 
					
						
							|  |  |  |     // NOTE: `redirect_uri` itself may also contain URI-encoded components
 | 
					
						
							|  |  |  |     //
 | 
					
						
							|  |  |  |     // NOTE: This probably shouldn't be done in the browser because the server
 | 
					
						
							|  |  |  |     //   needs to initiate the state. If it is done in a browser, the browser
 | 
					
						
							|  |  |  |     //   should probably request 'state' from the server beforehand
 | 
					
						
							|  |  |  |     //
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     throw new Error("not implemented"); | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-08 04:18:15 -05:00
										 |  |  |   core.urls.authorizationRedirect = function (directive, opts) { | 
					
						
							| 
									
										
										
										
											2017-01-17 22:29:46 -05:00
										 |  |  |     //console.log('[authorizationRedirect]');
 | 
					
						
							|  |  |  |     //
 | 
					
						
							|  |  |  |     // Example Authorization Redirect - from Browser to Consumer API
 | 
					
						
							|  |  |  |     // (for generating a session securely on your own server)
 | 
					
						
							|  |  |  |     //
 | 
					
						
							|  |  |  |     // i.e. GET https://<<CONSUMER>>.com/api/org.oauth3.consumer/authorization_redirect/<<PROVIDER>>.com
 | 
					
						
							|  |  |  |     //
 | 
					
						
							|  |  |  |     // GET https://myapp.com/api/org.oauth3.consumer/authorization_redirect/`encodeURIComponent('example.com')`
 | 
					
						
							|  |  |  |     //  &scope=`encodeURIComponent('profile.login profile.email')`
 | 
					
						
							|  |  |  |     //
 | 
					
						
							|  |  |  |     // (optional)
 | 
					
						
							| 
									
										
										
										
											2017-02-06 13:26:46 -07:00
										 |  |  |     //  &state=`cryptoutil.random().toString('hex')`
 | 
					
						
							| 
									
										
										
										
											2017-01-17 22:29:46 -05:00
										 |  |  |     //  &redirect_uri=`encodeURIComponent('https://myapp.com/oauth3.html')`
 | 
					
						
							|  |  |  |     //
 | 
					
						
							|  |  |  |     // NOTE: This is not a request sent to the provider, but rather a request sent to the
 | 
					
						
							|  |  |  |     // consumer (your own API) which then sets some state and redirects.
 | 
					
						
							|  |  |  |     // This will initiate the `authorization_code` request on your server
 | 
					
						
							|  |  |  |     //
 | 
					
						
							|  |  |  |     opts = opts || {}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     var scope = opts.scope || directive.authn_scope; | 
					
						
							|  |  |  |     var providerUri = directive.provider_uri; | 
					
						
							| 
									
										
										
										
											2017-02-06 13:26:46 -07:00
										 |  |  |     var params = { | 
					
						
							|  |  |  |       state: core.utils.randomState() | 
					
						
							|  |  |  |     , debug: opts.debug || undefined | 
					
						
							|  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2017-01-17 22:29:46 -05:00
										 |  |  |     var slimProviderUri = encodeURIComponent(providerUri.replace(/^(https?|spdy):\/\//, '')); | 
					
						
							| 
									
										
										
										
											2017-02-07 12:23:30 -05:00
										 |  |  |     var authorizationRedirect = opts.authorizationRedirect; | 
					
						
							| 
									
										
										
										
											2017-01-17 22:29:46 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (scope) { | 
					
						
							|  |  |  |       params.scope = scope; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (opts.redirectUri) { | 
					
						
							|  |  |  |       // this is really only for debugging
 | 
					
						
							|  |  |  |       params.redirect_uri = opts.redirectUri; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     // Note: the type check is necessary because we allow 'true'
 | 
					
						
							|  |  |  |     // as an automatic mechanism when it isn't necessary to specify
 | 
					
						
							|  |  |  |     if ('string' !== typeof authorizationRedirect) { | 
					
						
							|  |  |  |       // TODO oauth3.json for self?
 | 
					
						
							| 
									
										
										
										
											2017-01-31 19:12:31 -07:00
										 |  |  |       authorizationRedirect = (opts.appApiBase || getDefaultAppApiBase()) | 
					
						
							| 
									
										
										
										
											2017-01-17 22:29:46 -05:00
										 |  |  |         + '/api/org.oauth3.consumer/authorization_redirect/:provider_uri'; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     authorizationRedirect = authorizationRedirect | 
					
						
							|  |  |  |       .replace(/!(provider_uri)/, slimProviderUri) | 
					
						
							|  |  |  |       .replace(/:provider_uri/, slimProviderUri) | 
					
						
							|  |  |  |       .replace(/#{provider_uri}/, slimProviderUri) | 
					
						
							|  |  |  |       .replace(/{{provider_uri}}/, slimProviderUri) | 
					
						
							|  |  |  |       ; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return { | 
					
						
							|  |  |  |       url: authorizationRedirect + '?' + core.querystringify(params) | 
					
						
							|  |  |  |     , method: 'GET' | 
					
						
							| 
									
										
										
										
											2017-02-06 13:26:46 -07:00
										 |  |  |     , state: params.state    // this becomes browser_state
 | 
					
						
							| 
									
										
										
										
											2017-01-17 22:29:46 -05:00
										 |  |  |     , params: params  // includes scope, final redirect_uri?
 | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-08 04:18:15 -05:00
										 |  |  |   core.urls.implicitGrant = function (directive, opts) { | 
					
						
							| 
									
										
										
										
											2017-01-17 22:29:46 -05:00
										 |  |  |     //console.log('[implicitGrant]');
 | 
					
						
							|  |  |  |     //
 | 
					
						
							|  |  |  |     // Example Implicit Grant Request
 | 
					
						
							|  |  |  |     // (for generating a browser-only session, not a session on your server)
 | 
					
						
							|  |  |  |     //
 | 
					
						
							|  |  |  |     // GET https://example.com/api/org.oauth3.provider/authorization_dialog
 | 
					
						
							|  |  |  |     //  ?response_type=token
 | 
					
						
							|  |  |  |     //  &scope=`encodeURIComponent('profile.login profile.email')`
 | 
					
						
							| 
									
										
										
										
											2017-02-06 13:26:46 -07:00
										 |  |  |     //  &state=`cryptoutil.random().toString('hex')`
 | 
					
						
							| 
									
										
										
										
											2017-01-17 22:29:46 -05:00
										 |  |  |     //  &client_id=xxxxxxxxxxx
 | 
					
						
							|  |  |  |     //  &redirect_uri=`encodeURIComponent('https://myapp.com/oauth3.html')`
 | 
					
						
							|  |  |  |     //
 | 
					
						
							|  |  |  |     // NOTE: `redirect_uri` itself may also contain URI-encoded components
 | 
					
						
							|  |  |  |     //
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     opts = opts || {}; | 
					
						
							|  |  |  |     var type = 'authorization_dialog'; | 
					
						
							|  |  |  |     var responseType = 'token'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-10 22:23:21 -05:00
										 |  |  |     var redirectUri = opts.redirect_uri; | 
					
						
							| 
									
										
										
										
											2017-01-17 22:29:46 -05:00
										 |  |  |     var scope = opts.scope || directive.authn_scope; | 
					
						
							|  |  |  |     var args = directive[type]; | 
					
						
							|  |  |  |     var uri = args.url; | 
					
						
							| 
									
										
										
										
											2017-02-06 13:26:46 -07:00
										 |  |  |     var state = core.utils.randomState(); | 
					
						
							|  |  |  |     var params = { | 
					
						
							|  |  |  |       debug: opts.debug || undefined | 
					
						
							| 
									
										
										
										
											2017-02-07 19:24:44 -07:00
										 |  |  |     , client_uri: opts.client_uri || opts.clientUri || undefined | 
					
						
							| 
									
										
										
										
											2017-02-10 22:23:21 -05:00
										 |  |  |     , client_id: opts.client_id || opts.client_uri || undefined | 
					
						
							| 
									
										
										
										
											2017-02-06 13:26:46 -07:00
										 |  |  |     }; | 
					
						
							| 
									
										
										
										
											2017-01-17 22:29:46 -05:00
										 |  |  |     var result; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     params.state = state; | 
					
						
							|  |  |  |     params.response_type = responseType; | 
					
						
							|  |  |  |     if (scope) { | 
					
						
							| 
									
										
										
										
											2017-01-19 01:08:07 +00:00
										 |  |  |       params.scope = core.stringifyscope(scope); | 
					
						
							| 
									
										
										
										
											2017-01-17 22:29:46 -05:00
										 |  |  |     } | 
					
						
							|  |  |  |     if (!redirectUri) { | 
					
						
							| 
									
										
										
										
											2017-02-10 22:23:21 -05:00
										 |  |  |       // TODO consider making this optional
 | 
					
						
							|  |  |  |       console.error('missing redirect_uri'); | 
					
						
							| 
									
										
										
										
											2017-01-17 22:29:46 -05:00
										 |  |  |     } | 
					
						
							|  |  |  |     params.redirect_uri = redirectUri; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     uri += '?' + core.querystringify(params); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     result = { | 
					
						
							|  |  |  |       url: uri | 
					
						
							|  |  |  |     , state: state | 
					
						
							|  |  |  |     , method: args.method | 
					
						
							|  |  |  |     , query: params | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return result; | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-09 21:51:22 -05:00
										 |  |  |   core.urls.resolve = function (base, next) { | 
					
						
							|  |  |  |     if (/^https:\/\//i.test(next)) { | 
					
						
							|  |  |  |       return next; | 
					
						
							| 
									
										
										
										
											2017-01-17 22:29:46 -05:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-02-09 21:51:22 -05:00
										 |  |  |     return core.normalizeUrl(base) + '/' + core.normalizePath(next); | 
					
						
							| 
									
										
										
										
											2017-01-19 01:08:07 +00:00
										 |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-08 04:18:15 -05:00
										 |  |  |   core.urls.refreshToken = function (directive, opts) { | 
					
						
							| 
									
										
										
										
											2017-01-19 01:08:07 +00:00
										 |  |  |     // grant_type=refresh_token
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Example Refresh Token Request
 | 
					
						
							|  |  |  |     // (generally for 1st or 3rd party server-side, mobile, and desktop apps)
 | 
					
						
							|  |  |  |     //
 | 
					
						
							|  |  |  |     // POST https://example.com/api/oauth3/access_token
 | 
					
						
							|  |  |  |     //    { "grant_type": "refresh_token", "client_id": "<<id>>", "scope": "<<scope>>"
 | 
					
						
							|  |  |  |     //    , "username": "<<username>>", "password": "password" }
 | 
					
						
							|  |  |  |     //
 | 
					
						
							|  |  |  |     opts = opts || {}; | 
					
						
							|  |  |  |     var type = 'access_token'; | 
					
						
							|  |  |  |     var grantType = 'refresh_token'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     var scope = opts.scope || directive.authn_scope; | 
					
						
							|  |  |  |     var clientSecret = opts.appSecret || opts.clientSecret; | 
					
						
							|  |  |  |     var args = directive[type]; | 
					
						
							|  |  |  |     var params = { | 
					
						
							|  |  |  |       "grant_type": grantType | 
					
						
							| 
									
										
										
										
											2017-02-08 04:18:15 -05:00
										 |  |  |     , "refresh_token": opts.refresh_token || opts.refreshToken || (opts.session && opts.session.refresh_token) | 
					
						
							| 
									
										
										
										
											2017-01-19 01:08:07 +00:00
										 |  |  |     , "response_type": 'token' | 
					
						
							| 
									
										
										
										
											2017-02-08 04:18:15 -05:00
										 |  |  |     , "client_id": opts.appId || opts.app_id || opts.client_id || opts.clientId || opts.client_id || opts.clientId | 
					
						
							|  |  |  |     , "client_uri": opts.client_uri || opts.clientUri | 
					
						
							| 
									
										
										
										
											2017-01-19 01:08:07 +00:00
										 |  |  |     //, "scope": undefined
 | 
					
						
							|  |  |  |     //, "client_secret": undefined
 | 
					
						
							| 
									
										
										
										
											2017-02-06 13:26:46 -07:00
										 |  |  |     , debug: opts.debug || undefined | 
					
						
							| 
									
										
										
										
											2017-01-19 01:08:07 +00:00
										 |  |  |     }; | 
					
						
							|  |  |  |     var uri = args.url; | 
					
						
							|  |  |  |     var body; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-08 04:18:15 -05:00
										 |  |  |     // TODO not allowed in the browser
 | 
					
						
							| 
									
										
										
										
											2017-01-19 01:08:07 +00:00
										 |  |  |     if (clientSecret) { | 
					
						
							|  |  |  |       params.client_secret = clientSecret; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (scope) { | 
					
						
							|  |  |  |       params.scope = core.stringifyscope(scope); | 
					
						
							| 
									
										
										
										
											2017-01-17 22:29:46 -05:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if ('GET' === args.method.toUpperCase()) { | 
					
						
							|  |  |  |       uri += '?' + core.querystringify(params); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       body = params; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return { | 
					
						
							|  |  |  |       url: uri | 
					
						
							|  |  |  |     , method: args.method | 
					
						
							|  |  |  |     , data: body | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-08 04:18:15 -05:00
										 |  |  |   core.urls.logout = function (directive, opts) { | 
					
						
							| 
									
										
										
										
											2017-02-08 00:48:07 -05:00
										 |  |  |     opts = opts || {}; | 
					
						
							|  |  |  |     var type = 'logout'; | 
					
						
							|  |  |  |     var clientId = opts.appId || opts.clientId || opts.client_id; | 
					
						
							|  |  |  |     var args = directive[type]; | 
					
						
							|  |  |  |     var params = { | 
					
						
							|  |  |  |       client_id: opts.clientUri || opts.client_uri | 
					
						
							|  |  |  |     , debug: opts.debug || undefined | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |     var uri = args.url; | 
					
						
							|  |  |  |     var body; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (opts.clientUri) { | 
					
						
							|  |  |  |       params.client_uri = opts.clientUri; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (clientId) { | 
					
						
							|  |  |  |       params.client_id = clientId; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     args.method = (args.method || 'GET').toUpperCase(); | 
					
						
							|  |  |  |     if ('GET' === args.method) { | 
					
						
							|  |  |  |       uri += '?' + core.querystringify(params); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       body = params; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return { | 
					
						
							|  |  |  |       url: uri | 
					
						
							|  |  |  |     , method: args.method || 'GET' | 
					
						
							|  |  |  |     , data: body | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-17 22:29:46 -05:00
										 |  |  |   exports.OAUTH3 = exports.OAUTH3 || { core: core }; | 
					
						
							|  |  |  |   exports.OAUTH3_CORE = core.OAUTH3_CORE = core; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if ('undefined' !== typeof module) { | 
					
						
							|  |  |  |     module.exports = core; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | }('undefined' !== typeof exports ? exports : window)); |