From 1425d02f654a283b22ca5ededc213c725862f65d Mon Sep 17 00:00:00 2001 From: AJ ONeal Date: Mon, 13 Feb 2017 12:46:12 -0500 Subject: [PATCH 1/4] .meta -> .token --- oauth3.core.js | 4 ++-- oauth3.core.provider.js | 8 +++++--- oauth3.js | 14 +++++++------- oauth3.provider.js | 3 +++ 4 files changed, 17 insertions(+), 12 deletions(-) diff --git a/oauth3.core.js b/oauth3.core.js index 0c2b426..a280465 100644 --- a/oauth3.core.js +++ b/oauth3.core.js @@ -175,10 +175,10 @@ , signature: parts[2] // should remain url-safe base64 }; } - , getFreshness: function (meta, staletime, now) { + , getFreshness: function (tokenMeta, staletime, now) { staletime = staletime || (15 * 60); now = now || Date.now(); - var fresh = ((parseInt(meta.exp, 10) || 0) - Math.round(now / 1000)); + var fresh = ((parseInt(tokenMeta.exp, 10) || 0) - Math.round(now / 1000)); if (fresh >= staletime) { return 'fresh'; diff --git a/oauth3.core.provider.js b/oauth3.core.provider.js index 6f657f8..86ddfeb 100644 --- a/oauth3.core.provider.js +++ b/oauth3.core.provider.js @@ -158,7 +158,7 @@ var url = core.urls.resolve(directive.issuer, directive.grants.url) .replace(/(:azp|:client_id)/g, core.normalizeUri(opts.client_id || opts.client_uri)) - .replace(/(:sub|:account_id)/g, opts.session.meta.sub) + .replace(/(:sub|:account_id)/g, opts.session.token.sub) ; var data = { client_id: opts.client_id @@ -206,12 +206,14 @@ //$('.js-user-avatar').attr('src', userAvatar); + /* console.log('grants options'); console.log(loc.hash); console.log(loc.search); console.log(clientObj); - console.log(session.meta); + console.log(session.token); console.log(window.document.referrer); + */ return OAUTH3.requests.grants(CONFIG.host, { method: 'GET' @@ -256,7 +258,7 @@ //return generateToken(session, clientObj); } - grants = grantResults.originalData.grants.filter(function (grant) { + grants = (grantResults.originalData||grantResults.data).grants.filter(function (grant) { if (clientUri === (grant.azp || grant.oauth_client_id || grant.oauthClientId)) { return true; } diff --git a/oauth3.js b/oauth3.js index 388f914..972095c 100644 --- a/oauth3.js +++ b/oauth3.js @@ -51,7 +51,7 @@ console.warn('[oauth3.hooks.checkSession] no session'); return oauth3.PromiseA.resolve(null); } - var freshness = oauth3.core.jwt.getFreshness(preq.session.meta, opts.staletime); + var freshness = oauth3.core.jwt.getFreshness(preq.session.token, opts.staletime); console.info('[oauth3.hooks.checkSession] freshness', freshness, preq.session); switch (freshness) { @@ -118,11 +118,11 @@ oldSession.client_uri = clientUri; // azp // info about the newly-discovered token - oldSession.meta = core.jwt.decode(oldSession.access_token).payload; + oldSession.token = oldSession.meta = core.jwt.decode(oldSession.access_token).payload; - oldSession.meta.sub = oldSession.meta.sub || oldSession.meta.acx.id; - oldSession.meta.client_uri = clientUri; - oldSession.meta.provider_uri = providerUri; + oldSession.token.sub = oldSession.token.sub || oldSession.token.acx.id; + oldSession.token.client_uri = clientUri; + oldSession.token.provider_uri = providerUri; if (oldSession.refresh_token || oldSession.refreshToken) { oldSession.refresh = core.jwt.decode(oldSession.refresh_token || oldSession.refreshToken).payload; @@ -200,7 +200,7 @@ function lintAndRequest(preq) { function goGetHer() { if (preq.session) { - // TODO check session.meta.aud against preq.url to make sure they match + // TODO check session.token.aud against preq.url to make sure they match console.warn("[security] session audience checking has not been implemented yet (it's up to you to check)"); preq.headers = preq.headers || {}; preq.headers.Authorization = 'Bearer ' + (preq.session.access_token || preq.session.accessToken); @@ -285,7 +285,7 @@ return { client: oauth3.hooks.getGrants(opts.client_id + '-client') - , grants: oauth3.hooks.getGrants(opts.client_id) + , grants: oauth3.hooks.getGrants(opts.client_id) || [] }; }); }); diff --git a/oauth3.provider.js b/oauth3.provider.js index 4af4083..dbaf8ea 100644 --- a/oauth3.provider.js +++ b/oauth3.provider.js @@ -47,6 +47,9 @@ return; } + console.warn("What are grants? Baby don't hurt me. Don't hurt me. No more."); + console.warn(grants); + myGrants = grants.grants.filter(function (grant) { if (clientUri === (grant.azp || grant.oauth_client_id || grant.oauthClientId)) { return true; From 35e2a29e4c2d7ee3bca278ce76722c36e3ad03c7 Mon Sep 17 00:00:00 2001 From: AJ ONeal Date: Mon, 13 Feb 2017 13:01:13 -0500 Subject: [PATCH 2/4] refreshSession on login as well --- oauth3.browser.js | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/oauth3.browser.js b/oauth3.browser.js index a8a9218..ddc512c 100644 --- a/oauth3.browser.js +++ b/oauth3.browser.js @@ -118,6 +118,15 @@ resolve(tokens); }; }); + }).then(function (tokens) { + return OAUTH3.hooks.refreshSession( + opts.session || { + provider_uri: providerUri + , client_id: opts.client_id + , client_uri: opts.client_uri || opts.clientUri + } + , tokens + ); }); } @@ -260,9 +269,19 @@ } return browser.frameRequest(prequest.url, prequest.state, opts); + }).then(function (tokens) { + return OAUTH3.hooks.refreshSession( + opts.session || { + provider_uri: providerUri + , client_id: opts.client_id + , client_uri: opts.client_uri || opts.clientUri + } + , tokens + ); }); } , implicitGrant: function (providerUri, opts) { + // TODO let broker=true change behavior to open discover inline with frameRequest // TODO OAuth3 provider should use the redirect URI as the appId? return OAUTH3.discover(providerUri, opts).then(function (directive) { var prequest = OAUTH3_CORE.urls.implicitGrant( @@ -276,6 +295,15 @@ } return browser.frameRequest(prequest.url, prequest.state, opts); + }).then(function (tokens) { + return OAUTH3.hooks.refreshSession( + opts.session || { + provider_uri: providerUri + , client_id: opts.client_id + , client_uri: opts.client_uri || opts.clientUri + } + , tokens + ); }); } , logout: function (providerUri, opts) { From a449358dd6e0313eee8a0480f1a91512a699f7ae Mon Sep 17 00:00:00 2001 From: AJ ONeal Date: Mon, 13 Feb 2017 14:34:26 -0500 Subject: [PATCH 3/4] move .well-known/oauth3 to assets/org.oauth3/.well-known/oauth3 --- .well-known/oauth3/callback.html | 21 ++ .well-known/oauth3/callback.js | 66 ++++++ .well-known/oauth3/crossdomain.html | 0 .well-known/oauth3/crossdomain.js | 0 .well-known/oauth3/directives.js | 330 ++++++++++++++++++++++++++++ .well-known/oauth3/directives.json | 9 + .well-known/oauth3/index.html | 68 ++++++ .well-known/oauth3/logout.html | 0 .well-known/oauth3/logout.js | 0 9 files changed, 494 insertions(+) create mode 100644 .well-known/oauth3/callback.html create mode 100644 .well-known/oauth3/callback.js create mode 100644 .well-known/oauth3/crossdomain.html create mode 100644 .well-known/oauth3/crossdomain.js create mode 100644 .well-known/oauth3/directives.js create mode 100644 .well-known/oauth3/directives.json create mode 100644 .well-known/oauth3/index.html create mode 100644 .well-known/oauth3/logout.html create mode 100644 .well-known/oauth3/logout.js diff --git a/.well-known/oauth3/callback.html b/.well-known/oauth3/callback.html new file mode 100644 index 0000000..6cea1d3 --- /dev/null +++ b/.well-known/oauth3/callback.html @@ -0,0 +1,21 @@ + + + + + + Redirecting... + + + + Redirecting... + + + + + + + diff --git a/.well-known/oauth3/callback.js b/.well-known/oauth3/callback.js new file mode 100644 index 0000000..a9c7c88 --- /dev/null +++ b/.well-known/oauth3/callback.js @@ -0,0 +1,66 @@ +(function () { + "use strict"; + + var loc = window.location; + var loginWinObj = window.OAUTH3_CORE.queryparse(loc.hash || loc.search); + var prefix = "(" + window.location.hostname + ") [.well-known/oauth3/callback.html]"; + + if (loginWinObj.debug) { + console.warn(prefix, "DEBUG MODE ENABLED. Automatic redirects disabled."); + } + // '--oauth3-callback-' prefix exist for security so that an attacker can't social engineer execution an arbitrary function + // TODO finalize name of '--oauth3-callback-', this will be a defacto standard + // TODO maybe call it 'self-xss-' or 'hack-my-account-' to discourage people from doing dumb things? + var callbackName = '--oauth3-callback-' + loginWinObj.state; + + console.log(prefix, loc.href); + console.log('Parsed URL Obj: ', loginWinObj); + console.log('callbackName: ', callbackName); + + window.oauth3complete = function () { + // The hacks that used to be necessary for this on iOS should no longer be necessary in iOS 9+ + // see https://bugs.chromium.org/p/chromium/issues/detail?id=136610 and https://crbug.com/423444 + // TODO Should we still create an abstraction for older versions? + if (window.parent) { + // iframe + try { + window.parent[callbackName](loginWinObj); + return; + } catch(e) { + console.warn(e); + } + } + + if (window.opener) { + try { + window.opener[callbackName](loginWinObj); + return; + } catch(e) { + console.warn(e); + } + } + + console.error("neither window.parent nor window.opener existed to complete callback"); + + /* + // the caller should close (or signal to close) the window + try { + window.close(); + } catch (err) { + console.log('Error: ', err); + } + */ + }; + + if (!loginWinObj.debug) { + window.oauth3complete(); + } + else { + document.body.innerHTML = window.location.hostname + window.location.pathname + + '

You\'ve passed the \'debug\' parameter so we\'re pausing' + + ' to let you look at logs or whatever it is that you intended to do.' + + '

Continue with callback: javascript:window.oauth3complete()'; + return; + } + +}()); diff --git a/.well-known/oauth3/crossdomain.html b/.well-known/oauth3/crossdomain.html new file mode 100644 index 0000000..e69de29 diff --git a/.well-known/oauth3/crossdomain.js b/.well-known/oauth3/crossdomain.js new file mode 100644 index 0000000..e69de29 diff --git a/.well-known/oauth3/directives.js b/.well-known/oauth3/directives.js new file mode 100644 index 0000000..43e8efc --- /dev/null +++ b/.well-known/oauth3/directives.js @@ -0,0 +1,330 @@ +(function () { + 'use strict'; + + console.log('[DAPLIE oauth3 directives.js]'); + console.log(window.location); + + var iter = 0; + + function main() { + + var rpc = {}; + //var myself = location.protocol + '//' + location.host + location.pathname; + var incoming; + var forwarding = {}; + var err; + var browserState; + var browserCallback; + var action; + + function parseParams() { + var params = {}; + + function parseParamsString(str) { + str.substr(1).split('&').filter(function (el) { return el; }).forEach(function (pair) { + pair = pair.split('='); + var key = decodeURIComponent(pair[0]); + var val = decodeURIComponent(pair[1]); + + if (params[key]) { + console.warn("overwriting key '" + key + "' '" + params[key] + "'"); + } + params[key] = val; + }); + } + + parseParamsString(window.location.search); + // handle cases where hash is treated like it's own href + // TODO /#/?search=blah + parseParamsString(window.location.hash); + + return params; + } + + function querystringify(params) { + var arr = []; + + Object.keys(params).forEach(function (k) { + arr.push(encodeURIComponent(k) + '=' + encodeURIComponent(params[k])); + }); + + return arr.join('&'); + } + + function phoneAway(/*redirectURi, params*/) { + // TODO test for ? / # + window.location.href = incoming.redirect_uri + '#' + querystringify(forwarding); + } + + function lintAndSetRedirectable(browserState, params) { + if (!params.redirect_uri) { + window.alert('redirect_uri not defined'); + err = new Error('redirect_uri not defined'); + console.error(err.message); + console.warn(err.stack); + params.redirect_uri = document.referer; + return false; + } + + if (!browserState) { + forwarding.error = "E_NO_BROWSER_STATE"; + forwarding.error_description = "you must specify a state parameter"; + return false; + } + + localStorage.setItem('oauth3.states.' + browserState, JSON.stringify(params)); + return true; + } + + function redirectCallback() { + var redirect_uri = incoming.redirect_uri; + forwarding.callback = browserState; + forwarding.action = 'close'; + + var url = redirect_uri + '#' + querystringify(forwarding); + + console.log('[debug] redirect_uri + params:', url); + window.location.href = url; + setTimeout(function () { + if (iter >= 3) { + console.log("dancing way too much... stopping now"); + return; + } + iter += 1; + console.log("I'm dancing by myse-e-elf"); + // in case I'm redirecting to myself + main(); + }, 0); + } + + rpc = {}; + + // Act as a provider and log the user out + rpc.logout = function (browserState, incoming) { + var url; + if (!lintAndSetRedirectable(browserState, incoming)) { + // TODO fail + } + + localStorage.setItem('oauth3.states.' + browserState, JSON.stringify(incoming)); + url = '/#/logout/' + browserState; + + // TODO specify specific account or all? + window.location.href = url; + setTimeout(function () { + // in case I'm redirecting to myself + main(); + }, 0); + }; + + // Act as a provider and inform the consumer the logout is complete + rpc.logout_callback = function (browserState/*, incoming*/) { + // TODO pass redirect_uri and state through here so we can avoid localStorage + var forwarding = {}; + var originalRequest; + + if (!browserState) { + forwarding.error = "E_NO_BROWSER_STATE"; + forwarding.error_description = "you must specify a state parameter"; + if (incoming.redirect_uri) { + phoneAway(incoming.redirect_uri, forwarding); + } + return; + } + + originalRequest = JSON.parse(localStorage.getItem('oauth3.states.' + browserState)); + forwarding.action = 'close'; + forwarding.state = browserState; + //phoneAway(originalRequest.redirect_uri, forwarding); + window.location.href = originalRequest.redirect_uri + '#' + querystringify(forwarding); + }; + + rpc.directives = function (browserState, incoming) { + if (!lintAndSetRedirectable(browserState, incoming)) { + phoneAway(); + return; + } + + var updatedAt = new Date(localStorage.getItem('oauth3.directives.updated_at')).valueOf(); + var fresh = (Date.now() - updatedAt) < (24 * 60 * 60 * 1000); + var directives = localStorage.getItem('oauth3.directives'); + var redirected = false; + + function redirectIf() { + if (redirected) { + return; + } + + redirected = true; + redirectCallback(); + } + + if (directives) { + forwarding.directives = directives; + redirectIf(); + if (fresh) { + return; + } + } + + var req = new XMLHttpRequest(); + req.open('GET', '.well-known/oauth3.json', true); + req.addEventListener('readystatechange', function () { + if (4 !== req.readyState) { + return; + } + + if (200 !== req.status) { + forwarding.error = "E_STATUS_" + req.status; + forwarding.error_description = "expected 200 OK json or text response for oauth3.json but got '" + req.status + "'"; + redirectIf(); + return; + } + + try { + directives = btoa(JSON.stringify(JSON.parse(req.responseText))); + forwarding.directives = directives; + forwarding.callback = browserState; + localStorage.setItem('oauth3.directives', directives); + localStorage.setItem('oauth3.directives.updated_at', new Date().toISOString()); + } catch(e) { + forwarding.error = "E_PARSE_JSON"; + forwarding.error_description = e.message; + console.error(forwarding.error); + console.error(forwarding.error_description); + console.error(req.responseText); + } + + redirectIf(); + }); + req.send(); + }; + + // the provider is contacting me + rpc.close = function (browserState, incoming) { + incoming.callback = browserState; + catchAll(); + }; + // the provider is contacting me + rpc.redirect = function (/*browserState, incoming*/) { + catchAll(); + }; + + function catchAll() { + function phoneHome() { + if (browserCallback === 'completeLogin') { + // Deprecated + console.log('[deprecated] callback completeLogin'); + (window.opener||window.parent).completeLogin(null, null, incoming); + } else { + console.log('[DEBUG] I would be closed by my parent now'); + console.log('__oauth3_' + browserCallback); + console.log(window.opener && window.opener['__oauth3_' + browserCallback]); + console.log(window.parent && window.parent['__oauth3_' + browserCallback]); + console.log(incoming); + (window.opener||window.parent)['__oauth3_' + browserCallback](incoming); + } + } + + if (!(incoming.browser_state || incoming.state)) { + window.alert("callback URLs should include 'browser_state' (authorization code)" + + " or 'state' (implicit grant))"); + } + + setTimeout(function () { + // opener is for popup window, new tab + // parent is for iframe + phoneHome(); + }, 10); + + // iOS Webview (namely Chrome) workaround + setTimeout(function () { + console.log('I would close now'); + // XXX OAUTH3 DEBUG FRAME XXX // make this easy to find + window.open('', '_self', ''); + window.close(); + }, 50); + + setTimeout(function () { + var i; + var len = localStorage.length; + var key; + var json; + var fresh; + + for (i = 0; i < len; i += 1) { + key = localStorage.key(i); + // TODO check updatedAt + if (/^oauth3\./.test(key)) { + try { + json = localStorage.getItem(key); + if (json) { + json = JSON.parse(json); + } + } catch (e) { + // ignore + json = null; + } + + fresh = json && (Date.now() - json.updatedAt < (5 * 60 * 1000)); + + if (!fresh) { + localStorage.removeItem(key); + } + } + } + forwarding.updatedAt = Date.now(); + localStorage.setItem('oauth3.' + (forwarding.browser_state || forwarding.state), JSON.stringify(forwarding)); + }, 0); + + } + + function parseAction(params) { + if (params.action) { + return params.action; + } + + if (params.close) { + return 'close'; + } + if (params.logout_callback) { + return 'logout_callback'; + } + if (params.logout) { + return 'logout'; + } + if (params.callback) { + return 'close'; + } + if (params.directives) { + return 'directives'; + } + + return 'redirect'; + } + + incoming = parseParams(); + browserState = incoming.browser_state || incoming.state; + action = parseAction(incoming); + forwarding.url = window.location.href; + forwarding.browser_state = browserState; + forwarding.state = browserState; + + if (!incoming.provider_uri) { + browserCallback = incoming.callback || browserState; + } else { + // deprecated + browserCallback = 'completeLogin'; + } + + console.log('[debug]', action, incoming); + + if (rpc[action]) { + rpc[action](browserState, incoming); + } else { + window.alert('unsupported action'); + } + } + + main(); +}()); diff --git a/.well-known/oauth3/directives.json b/.well-known/oauth3/directives.json new file mode 100644 index 0000000..d482bc8 --- /dev/null +++ b/.well-known/oauth3/directives.json @@ -0,0 +1,9 @@ +{ "authorization_dialog": { "url": "#/authorization_dialog" } +, "access_token": { "method": "POST", "url": "api/org.oauth3.provider/access_token" } +, "otp": { "method": "POST" , "url": "api/org.oauth3.provider/otp" } +, "credential_otp": { "method": "POST" , "url": "api/org.oauth3.provider/otp" } +, "credential_meta": { "url": "api/org.oauth3.provider/logins/meta/:type/:id" } +, "credential_create": { "method": "POST" , "url": "api/org.oauth3.provider/logins" } +, "grants": { "method": "GET", "url": "api/org.oauth3.provider/grants/:azp/:sub" } +, "authorization_decision": { "method": "POST", "url": "api/org.oauth3.provider/authorization_decision" } +} diff --git a/.well-known/oauth3/index.html b/.well-known/oauth3/index.html new file mode 100644 index 0000000..81f4905 --- /dev/null +++ b/.well-known/oauth3/index.html @@ -0,0 +1,68 @@ + + + + + + + OAuth3 RPC + + + + + + diff --git a/.well-known/oauth3/logout.html b/.well-known/oauth3/logout.html new file mode 100644 index 0000000..e69de29 diff --git a/.well-known/oauth3/logout.js b/.well-known/oauth3/logout.js new file mode 100644 index 0000000..e69de29 From 3bded288470dee82f60f3ab5fe16d5fa4929e84e Mon Sep 17 00:00:00 2001 From: AJ ONeal Date: Mon, 13 Feb 2017 14:35:48 -0500 Subject: [PATCH 4/4] WIP cleanup and doc --- README.md | 101 ++++++++++++++++++++++++++++++++++++++++ oauth3.browser.js | 33 ++++++++----- oauth3.core.provider.js | 2 +- oauth3.js | 15 +++--- 4 files changed, 133 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 5eda2ef..7026037 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,88 @@ oauth3.js ========= +The world's smallest, fastest, and most secure OAuth3 (and OAuth2) JavaScript implementation +(Yes! works in browsers and node.js with no extra dependencies or bloat and no hacks!) + +Instead of bloating your webapp and ruining the mobile experience, +you can use a single, small javascript file for all OAuth3 providers +(and almost all OAuth2 providers) with a seemless experience. + +Also, instead of complicated (or worse - insecure) CLI and Desktop login methods, +you can easily integrate an OAuth3 flow (or broker) into any node.js app (i.e. Electron, Node-Webkit) +with 0 pain. + +Installation +------------ + +**Easy Install** for Web Apps (including Mobile): + +1. In your web site / web app folder create a folder called `assets` +2. Inside of `assets` create another folder called `org.oauth3` +3. Download [oauth.js-v1.zip](https://git.daplie.com/Daplie/oauth3.js/repository/archive.zip?ref=v1) +4. Double-click to unzip the folder. +5. Copy `oauth3.js` and `oauth3.browser.js` to `assets/org.oauth3` + +**Advanced Installation with `git`** + +``` +# Navigate to your web site or web app +pushd /path/to/your/web/app + + +# clone the project as assets/org.oauth3 +mkdir -p assets +git clone git@git.daplie.com:Daplie/oauth3.js.git assets/org.oauth3 +pushd assests/org.oauth3 +git checkout v1 +popd + + +# symlink `.well-known/oauth3` to `assets/org.oauth3/.well-known/oauth3` +mkdir -p .well-known +ln -sf ../assets/org.oauth3/.well-known/oauth3 .well-known/oauth3 +``` + +**Advanced Installation with `bower`** + +``` +# Install to bower_components +bower install oauth3 + + +# create a `.well-known` folder and an `assets` folder +mkdir -p .well-known assets + + +# symlink `.well-known/oauth3` to `bower_components/oauth3/.well-known/oauth3` +ln -sf ../bower_components/oauth3/.well-known/oauth3 .well-known/oauth3 + + +# symlink `assets/org.oauth3` to `bower_components/oauth3` +ln -sf ../bower_components/oauth3/.well-known/oauth3 .well-known/oauth3 +ln -sf ../bower_components/oauth3 assets/org.oauth3 +``` + +Usage +----- + +Update your HTML to include the the following script tags: + +``` + + +``` + +If you use jQuery you should also include + +``` + +``` + + +Stable API +---------- + Public utilities for browser and node.js: * `querystringify(query)` @@ -14,6 +96,25 @@ URL generation: * `loginCode` * `resourceOwnerPassword` +Roadmap +------- + +* v1.0 - "implicit grant" authorization with examples + * popup + * iframe + * documentation +* v1.1 - cleanup + * in-flow discovery + * smallest possible size + * inline windowing (non-promisable callback) + * async set/get + * logout +* v1.2 - features + * "authorization code" flow + * "broker" flow +* v1.3 - features + * remove grants + URI vs URL ---------- diff --git a/oauth3.browser.js b/oauth3.browser.js index ddc512c..7805971 100644 --- a/oauth3.browser.js +++ b/oauth3.browser.js @@ -13,7 +13,8 @@ } var browser = exports.OAUTH3_BROWSER = { - clientUri: function (location) { + window: window + , clientUri: function (location) { return OAUTH3_CORE.normalizeUri(location.host + location.pathname); } , discover: function (providerUri, opts) { @@ -133,12 +134,21 @@ , frameRequest: function (url, state, opts) { var promise; - if ('background' === opts.type) { + if (!opts.windowType) { + opts.windowType = 'popup'; + } + + if ('background' === opts.windowType) { promise = browser.insertIframe(url, state, opts); - } else if ('popup' === opts.type) { + } else if ('popup' === opts.windowType) { promise = browser.openWindow(url, state, opts); + } else if ('inline' === opts.windowType) { + // callback function will never execute and would need to redirect back to current page + // rather than the callback.html + url += '&original_url=' + browser.window.location.href; + promise = browser.window.location = url; } else { - throw new Error("login framing method not specified or not type yet implemented"); + throw new Error("login framing method options.windowType not specified or not type yet implemented"); } return promise.then(function (params) { @@ -254,7 +264,7 @@ // // Logins // - , requests: { + , authn: { authorizationRedirect: function (providerUri, opts) { // TODO get own directives @@ -483,14 +493,14 @@ , code: data.code - , access_token: data.accessToken - , expires_at: data.expiresAt - , expires_in: data.expiresIn + , access_token: data.access_token + , expires_at: data.expires_at + , expires_in: data.expires_in , scope: data.scope - , refresh_token: data.refreshToken - , refresh_expires_at: data.refreshExpiresAt - , refresh_expires_in: data.refreshExpiresIn + , refresh_token: data.refresh_token + , refresh_expires_at: data.refresh_expires_at + , refresh_expires_in: data.refresh_expires_in }); if ('token' === scope.appQuery.response_type) { @@ -535,6 +545,7 @@ }, 50); } }; + browser.requests = browser.authn; Object.keys(browser).forEach(function (key) { if ('requests' === key) { diff --git a/oauth3.core.provider.js b/oauth3.core.provider.js index 86ddfeb..4626d37 100644 --- a/oauth3.core.provider.js +++ b/oauth3.core.provider.js @@ -233,7 +233,7 @@ console.log(grantResults); if (grantResults.data.error) { - window.alert('grantResults: ' + grantResults.data.errorDescription || grantResults.data.error.message); + window.alert('grantResults: ' + grantResults.data.error_description || grantResults.data.error.message); return; } diff --git a/oauth3.js b/oauth3.js index 972095c..3406c05 100644 --- a/oauth3.js +++ b/oauth3.js @@ -27,6 +27,7 @@ }; // TODO move recase out + /* oauth3._recaseRequest = function (recase, req) { // convert JavaScript camelCase to oauth3/ruby snake_case if (req.data && 'object' === typeof req.data) { @@ -44,6 +45,7 @@ } return resp; }; + */ oauth3.hooks = { checkSession: function (preq, opts) { @@ -193,9 +195,9 @@ // TODO simplify (nix recase) oauth3.provideRequest = function (rawRequest, opts) { opts = opts || {}; - var Recase = exports.Recase || require('recase'); + //var Recase = exports.Recase || require('recase'); // TODO make insensitive to providing exceptions - var recase = Recase.create({ exceptions: {} }); + //var recase = Recase.create({ exceptions: {} }); function lintAndRequest(preq) { function goGetHer() { @@ -236,9 +238,10 @@ return lintAndRequest(req, opts); } - req = oauth3._recaseRequest(recase, req); + //req = oauth3._recaseRequest(recase, req); return lintAndRequest(req, opts).then(function (res) { - return oauth3._recaseResponse(recase, res); + //return oauth3._recaseResponse(recase, res); + return res; }); }; @@ -295,10 +298,10 @@ var prequest = core.urls.loginCode(directive, opts); return oauth3.request(prequest).then(function (res) { - // result = { uuid, expiresAt } + // result = { uuid, expires_at } return { otpUuid: res.data.uuid - , otpExpires: res.data.expiresAt + , otpExpires: res.data.expires_at }; }); });