Compare commits

...

26 Commits

Author SHA1 Message Date
AJ ONeal 8555d3673a forward-compat 2018-07-06 07:20:43 +00:00
AJ ONeal ff50c74a56 OAuth3 branding 2018-07-06 07:12:34 +00:00
AJ ONeal 9760bcf6c1 Merge branch 'v1.2' into playground 2017-11-29 04:07:43 +00:00
AJ ONeal c90fd2a6f4 oauth3_authn -> authn@oauth3.org 2017-11-29 02:10:00 +00:00
AJ ONeal f069314e76 fix typo for scope 2017-11-17 17:44:10 +00:00
AJ ONeal 0727c3a6c9 add discover scope example 2017-11-17 17:43:32 +00:00
AJ ONeal 242c0e3abb move session 2017-11-17 06:17:30 +00:00
AJ ONeal ece06b8463 profile updates 2017-11-17 06:15:57 +00:00
AJ ONeal 980895992a add intro page, split playground 2017-11-17 02:25:04 +00:00
AJ ONeal 9aaabeb908 more token debuggers 2017-11-16 22:21:02 +00:00
AJ ONeal 4ab4ad0ac0 List App Grants 2017-11-16 05:32:23 +00:00
AJ ONeal 0ff3a2e3ce some typo fixes 2017-11-16 03:23:35 +00:00
AJ ONeal 4b6a8f7316 view session info 2017-11-16 03:00:11 +00:00
AJ ONeal 998c652969 show otp 2017-11-14 23:40:32 +00:00
drewwarren 87820b3d24 Merge branch 'remember-me' of OAuth3/issuer.html into v1.2 2017-11-14 20:12:39 +00:00
AJ ONeal db261147c2 WIP resource owner password 2017-11-14 20:02:01 +00:00
AJ ONeal 6eb5ea0f3d tools to debug scope 2017-11-14 19:55:06 +00:00
John Shaver 23318c01f0 fixed the initialized state of the remember-me checkbox 2017-11-14 08:12:51 -08:00
John Shaver ed1c3374dd Fixed remember me checkbox. 2017-11-14 07:39:12 -08:00
John Shaver 9dbc2b5664 Added some error handling so errors dissapearing. 2017-11-14 07:38:34 -08:00
AJ ONeal 84a8090d49 show session 2017-11-14 00:59:43 +00:00
AJ ONeal 6105637cc5 Merge branch 'v1.2' into playground 2017-11-13 23:25:36 +00:00
AJ ONeal c5cc2be470 opens authorization_dialog 2017-11-13 23:14:28 +00:00
AJ ONeal a16fbdd764 made playground form decent 2017-11-13 20:35:23 +00:00
AJ ONeal 23765a97ef begin OAuth3 Explorer & Playground 2017-11-09 03:44:13 +00:00
AJ ONeal 2500711b8c Welcome to the Playground! 2017-11-08 22:32:55 +00:00
11 changed files with 45203 additions and 58 deletions

1
.well-known Symbolic link
View File

@ -0,0 +1 @@
_apis

1
_apis/oauth3 Symbolic link
View File

@ -0,0 +1 @@
oauth3.org

1
_apis/org.oauth3 Symbolic link
View File

@ -0,0 +1 @@
oauth3.org

View File

@ -8,7 +8,7 @@
<!-- <link rel="stylesheet" type="text/css" href="/css/style.css"> --> <!-- <link rel="stylesheet" type="text/css" href="/css/style.css"> -->
<link rel="stylesheet" type="text/css" href="https://fonts.googleapis.com/css?family=Lato:300"> <link rel="stylesheet" type="text/css" href="https://fonts.googleapis.com/css?family=Lato:300">
<script src="https://use.fontawesome.com/3af0faae66.js"></script> <script src="https://use.fontawesome.com/3af0faae66.js"></script>
<link rel="stylesheet" type="text/css" href="/css/daplie-installer-overrides.css"> <!-- link rel="stylesheet" type="text/css" href="/css/daplie-installer-overrides.css" -->
</head> </head>
<body> <body>
@ -24,8 +24,8 @@
<!-- Step 5: ask for permissions --> <!-- Step 5: ask for permissions -->
<div class="dap-bordered js-userid-container"> <div class="dap-bordered js-userid-container">
<p class="org-title">daplie.me</p> <p class="org-title">OAuth3.org</p>
<p class="dap-centered-text dap-normal-text welcome-text center-it">Welcome to a new way to login. daplie.me helps you create an Internet ID that allows you to choose what info is shared about you when you login into a site or app online.</p> <p class="dap-centered-text dap-normal-text welcome-text center-it">Welcome to a new way to login. OAuth3.org helps you create an Internet ID that allows you to choose what info is shared about you when you login into a site or app online.</p>
<form method="post" action=""> <form method="post" action="">
<div class="form-group"> <div class="form-group">
<input type="email" class="form-control dap-input js-oauth3-email emailInput" placeholder="Enter an email address to start"></input> <input type="email" class="form-control dap-input js-oauth3-email emailInput" placeholder="Enter an email address to start"></input>
@ -46,7 +46,7 @@
</div> </div>
<div class="dap-bordered js-authn"> <div class="dap-bordered js-authn">
<p class="org-title">daplie.me</p> <p class="org-title">OAuth3.org</p>
<!-- <div class="dap-normal-text"> <!-- <div class="dap-normal-text">
<span class="fa fa-3x icon-centered-3x fa-purple fa-envelope"></span> <span class="fa fa-3x icon-centered-3x fa-purple fa-envelope"></span>
</div> </div>
@ -69,7 +69,7 @@
<img src="./img/pressed-check.png" class="check js-remember-status"> <img src="./img/pressed-check.png" class="check js-remember-status">
<!-- <span class="fa fa-2x fa-purple fa-square-o dap-remember-margin js-remember-status"></span> --> <!-- <span class="fa fa-2x fa-purple fa-square-o dap-remember-margin js-remember-status"></span> -->
<span class="dap-remember-me noselect">Remember this device.</span> <span class="dap-remember-me noselect">Remember this device.</span>
<input class="js-remember-checkbox hidden" type="checkbox"></input> <input class="js-remember-checkbox hidden" type="checkbox" checked></input>
</label> </label>
</div> </div>
<button type="submit" class="btn btn-primary submit-btn dap-full-button-green js-submit-code-btn" disabled>Submit</button> <button type="submit" class="btn btn-primary submit-btn dap-full-button-green js-submit-code-btn" disabled>Submit</button>
@ -86,7 +86,7 @@
</div> </div>
<div class="dap-bordered dap-normal-text js-authz"> <div class="dap-bordered dap-normal-text js-authz">
<p class="org-title">daplie.me</p> <p class="org-title">OAuth3.org</p>
<!-- <br> --> <!-- <br> -->
<!-- <div class="dap-user-plus-app"> <!-- <div class="dap-user-plus-app">
<span class="fa fa-3x fa-purple fa-user-circle"></span> <span class="fa fa-3x fa-purple fa-user-circle"></span>
@ -142,45 +142,62 @@
</div> </div>
</div> </div>
<div class="fade mock-bare"> <div class="fade js-playground" ng-app="oauth3Playground" ng-strict>
<div class="container"> <div class="container">
<div class="jumbotron"> <div class="jumbotron">
<h1>OAuth3 Playground</h1> <h1>OAuth3</h1>
<p>A (mostly) client-side authentication and authorization framework for decentralized peer-to-peer and federated networks.
</div>
<div class="row">
<div>
<h2>OAuth3 Test Bed</h2>
<!--
<a class="btn btn-primary" href="azp.html">Demo Authorized Party</a>
<a class="btn btn-primary" href="issuer.html">Demo Issuer</a>
-->
<a class="btn btn-primary" href="playground.html">Demo Authorized Party</a>
<a class="btn btn-primary" href="playground.html">Demo Issuer</a>
</div> </div>
<div class="row"> <div>
<div class="col-md-3"> <h2>Private, Peer-to-Peer, Anonymous: Pick any two... at a time</h2>
Login Status: <ul>
</div> <li>Privacy
<div class="col-md-9"> <li>Peer-to-Peer
... <li>Anonymity
</div> </ul>
</div> <p>OAuth3's federated design allows it to work in all 3 modes of decentralization:
<div class="row"> <ul>
<div class="col-md-3"> <li>Private, Peer-to-Peer (Trusted model)
Current Sessions: <!--
</div> (Public / Private Keypair model)
<div class="col-md-9"> For trusted parties OAuth3 defines how to exchange public keys on the client-side to
... ensure that a resource owner's assets can be retrieved, without any involved.
</div> -->
</div>
<div class="row"> <li>Private, Anonymous (Escrow / Broker model)
<div class="col-md-3"> <!--
Approved Devices: (Escrow / Broker model)
</div> When you want transactions to be both private and anonymous there
<div class="col-md-9"> must be a mutual trusted authority to broker the transaction to ensure privacy without
... disclosing identity. In the same way that a private escrow service can ensure a valid
</div> between two untrusted participants, <em>any</em> OAuth3 Issuer can broker identity and
</div> privilege transactions between two parties.
<div class="row"> -->
<div class="col-md-3">
Approved Applications: <li>Peer-to-Peer, Anonymous (Public Ledger model)
</div> <!--
<div class="col-md-9"> -->
... </ul>
</div>
</div> </div>
<h2>Authentication, simplified</h2>
<ul>
<li>A single implementation
<li>No developer keys (uses tls authentication)
<li>Smart scope discovery
</ul>
</div>
</div> </div>
</div> </div>

33889
js/angular-1.6.6.js Normal file

File diff suppressed because it is too large Load Diff

10075
js/angular-ui-router-1.0.10.js Normal file

File diff suppressed because it is too large Load Diff

View File

@ -68,7 +68,7 @@ $(function () {
// TODO casing // TODO casing
// TODO expiry calculation // TODO expiry calculation
// TODO leave this up to OAUTH3 // TODO leave this up to OAUTH3
session.provider_uri = session.provider_rui || CONFIG.host; session.provider_uri = session.provider_uri || CONFIG.host;
session.client_uri = session.client_uri || CONFIG.host; // same as provider in this case session.client_uri = session.client_uri || CONFIG.host; // same as provider in this case
} }
@ -94,6 +94,9 @@ $(function () {
// deprecated // deprecated
'oauth3_authn': "Basic secure authentication" 'oauth3_authn': "Basic secure authentication"
, 'auth@oauth3.org': "Basic secure authentication" , 'auth@oauth3.org': "Basic secure authentication"
, 'profile@oauth3.org': "Basic profile information"
, 'profile.email@oauth3.org': "Email address"
, 'profile.phone@oauth3.org': "Phone number"
, 'wallet': "Access to payments and subscriptions" , 'wallet': "Access to payments and subscriptions"
, 'bucket': "Access to file storage" , 'bucket': "Access to file storage"
, 'db': "Access to app data" , 'db': "Access to app data"
@ -118,7 +121,7 @@ $(function () {
, '*': "FULL ACCOUNT ACCESS" , '*': "FULL ACCOUNT ACCESS"
}; };
if ('oauth3_authn' === clientParams.scope) { if ('authn@oauth3.org' === (clientParams.scope||'').toString()) {
// implicit ppid grant is automatic // implicit ppid grant is automatic
console.warn('[security] fix scope checking on backend so that we can do automatic grants'); console.warn('[security] fix scope checking on backend so that we can do automatic grants');
// TODO check user preference if implicit ppid grant is allowed // TODO check user preference if implicit ppid grant is allowed
@ -362,7 +365,13 @@ $(function () {
function handleAuthorizationDialog() { function handleAuthorizationDialog() {
return getSession(CONFIG.host).then(function (session) { return getSession(CONFIG.host).then(function (session) {
return getGrants(session); return getGrants(session);
}).catch(function () { }).catch(function (e) {
if(e) {
console.error(
"Error authing current session. Requiring re-login. Message: "
, e.message
);
}
// TODO select the providers the client wants to show // TODO select the providers the client wants to show
// providers=daplie.com,facebook.com,google.com // etc // providers=daplie.com,facebook.com,google.com // etc
// TODO let the client specify switch_user // TODO let the client specify switch_user
@ -403,7 +412,8 @@ $(function () {
$('.mock-main').addClass('in'); $('.mock-main').addClass('in');
} else { } else {
console.log('[DEBUG] not an auth window'); console.log('[DEBUG] not an auth window');
$('.mock-bare').addClass('in'); $('.js-playground').addClass('in');
//window.PLAYGROUND();
} }
}); });
}); });

538
js/playground.js Normal file
View File

@ -0,0 +1,538 @@
(function () {
'use strict';
window.ngOauth3App = angular.module('oauth3Playground', [ 'oauth3.org' ])
//window.ngOauth3App = angular.module('oauth3Playground', [ 'ui.router' ])
/*
ngOauth3App.config(function($stateProvider) {
var helloState = {
name: 'hello',
url: '/hello',
template: '<h3>hello world!</h3>'
}
var aboutState = {
name: 'about',
url: '/about',
template: '<h3>Its the UI-Router hello world app!</h3>'
}
$stateProvider.state(helloState);
$stateProvider.state(aboutState);
});
*/
.controller('PlaygroundCtrl', [ '$timeout', 'azp@oauth3.org', function ($timeout, OAUTH3) {
// NOTE: This OAUTH3 is the same as window.OAUTH3, but with angular's promise injected
// TODO: how to load more than one version of oauth3 on the page (i.e. a vanilla version without angular entaglement)
var vm = this;
vm.framework = 'none';
vm.clientUri = OAUTH3.clientUri({ host: window.location.host });
vm.conf = { debug: undefined, client_id: vm.clientUri, client_uri: vm.clientUri, provider_uri: vm.clientUri };
vm.providerUri = vm.conf.client_uri;
// map of things being debounced presently
vm.debouncing = {};
vm.defaults = { provider: vm.conf.provider_uri, directives: null };
vm.defaults.scopes = [
{ name: 'profile@oauth3.org', desc: "Basic profile information", checked: true }
, { name: 'authn@oauth3.org', desc: "Basic secure authentication", checked: true }
//{ name: 'authn@oauth3.org', desc: "Basic secure authentication" }
, { name: 'photos@daplie.com', desc: "Access to photos" }
, { name: 'profile@oauth3.org', desc: "Access to basic profile info such as username, display_name, etc" }
, { name: 'dns', desc: "DNS records (A/AAAA, TXT, SRV, MX, etc)" }
, { name: '*', desc: "FULL ACCOUNT ACCESS" }
//, 'auth@oauth3.org': "Basic secure authentication"
//, 'profile.email@oauth3.org': "Email address"
//, 'profile.phone@oauth3.org': "Phone number"
];
vm.form = {};
vm.form.id = 'coolaj86@gmail.com';
vm.form.subject = '';
vm.form.userProvider = '';
vm.form.provider = 'sso.hellabit.com';
vm.form.scopes = '';
vm.locks = {};
vm.validated = {};
vm.responses = {};
//
// Convenience for our app
//
vm.fn = {};
vm.fn.updateUrls = function () {
Object.keys(vm.api.urls).forEach(function (key) {
var fn = vm.api.urls[key];
fn();
});
};
vm.fn._debounce = {};
vm.fn.debounceUi = function () {
if (vm.debouncing.user || vm.debouncing.provider) {
vm.locks['login'] = true;
} else {
vm.locks['login'] = false;
}
};
vm.fn.debounce = function (name, time) {
vm.debouncing[name] = true;
vm.fn.debounceUi();
$timeout.cancel(vm.fn._debounce[name]);
vm.fn._debounce[name] = $timeout(function () {
vm.debouncing[name] = false;
vm.fn.debounceUi();
// do nothing, just use promise
return;
}, time || 250);
return vm.fn._debounce[name];
}
vm.fn.changeUser = function () {
var parts = vm.form.id.split('@');
var user;
var provider;
if (/@/.test(vm.form.id)) {
// The username may have a single @, the provider may not
// user@thing.com@whatever.com -> user@thing.com, whatever.com
provider = parts.pop();
user = parts.join('');
} else {
//vm.form.hasUser = false;
user = '';
provider = parts.join('');
}
vm.form.subject = vm.form.id;
return vm.fn.debounce('provider', 250).then(function () {
var parts = vm.form.provider.split('.');
if (!vm.form.providerIndependent) {
vm.form.provider = provider;
}
vm.form.userProvider = provider;
// Careful: don't use state within a debounce function
// uses vm.form.provider for lookup
if (parts.length >= 2 && parts[parts.length - 1].length >= 2 && parts.every(function (p) {return p.length})) {
return vm.api.discover().then(function () {
console.log('[changeUser] vm.directives:');
console.log(vm.directives);
console.log(provider);
console.log(OAUTH3.uri.normalize(vm.directives.issuer));
if (vm.directives && provider === OAUTH3.uri.normalize(vm.directives.issuer)) {
vm.form.subject = user;
} else {
vm.form.subject = vm.form.id;
}
});
}
});
};
vm.fn.changeProvider = function () {
vm.form.providerIndependent = true;
var parts = vm.form.provider.split('.');
vm.fn.debounce('provider', 250).then(function () {
// Careful: don't use state within a debounce function
if (parts.length >= 2 && parts[parts.length - 1].length >= 2 && parts.every(function (p) {return p.length})) {
return vm.api.discover();
}
});
};
vm.fn.toggleAdvanced = function () {
vm.advanced = !vm.advanced;
vm.form.provider = vm.form.userProvider;
if (!vm.advanced) {
vm.form.providerIndependent = false;
vm.fn.changeUser();
}
};
vm.fn.updateDebug = function () {
if (!vm.conf.debug) {
vm.conf.debug = undefined;
}
};
vm.fn.updateScopes = function () {
var scopes = {};
(vm.scopes && vm.scopes.split(',') || []).forEach(function (name) {
scopes[name] = true;
});
vm.defaults.scopes.forEach(function (scope) {
if (scope.checked) {
scopes[scope.name] = true;
} else {
scopes[scope.name] = false;
}
});
vm.form.scopes = Object.keys(scopes).filter(function (key) {
return scopes[key];
}).map(function (key) {
return key;
}).join(',');
vm.fn.updateUrls(); // vm.api.urls.implicitGrant();
};
vm.fn.lock = function () {
vm._working = true;
};
vm.fn.unlock = function () {
vm._working = false;
};
vm.fn.clearError = function () {
vm.error = null;
};
vm.fn.clearDirectives = function () {
vm.directives = null;
};
// A place for all the generated urls
vm.urls = {};
//
// Wrap around the OAUTH3 APIs
//
vm.api = {};
vm.api.urls = {};
vm.api.authn = {};
vm.api.jwt = {};
vm.api.urls.credentialMeta = function () {
if (!vm.directives ||!vm.directives.credential_meta || !vm.form.id) { return; }
vm.urls.credentialMeta = OAUTH3.urls.credentialMeta(vm.directives, { email: vm.form.id });
};
vm.api.urls.otp = function () {
if (!vm.directives || !vm.form.id) { return; }
vm.urls.otp = OAUTH3.urls.otp(vm.directives, { email: vm.form.id });
};
vm.api.authn.otp = function () {
vm.fn.updateUrls(); // vm.api.urls.otp();
OAUTH3.authn.otp(vm.directives, { email: vm.form.id }).then(function (resp) {
vm.responses.otp = resp;
vm.form.otpUuid = resp.data.code_id;
console.log('vm.responses.otp: (' + typeof resp + ')');
console.log(vm.responses.otp);
console.log('vm.form.otpUuid:');
console.log(vm.form.otpUuid);
vm.fn.updateUrls(); // vm.api.urls.resourceOwnerPassword();
});
};
vm.api.authn.credentialMeta = function () {
vm.fn.updateUrls(); // vm.api.urls.credentialMeta();
OAUTH3.authn.loginMeta(vm.directives, { email: vm.form.id }).then(function () {
vm.fn.updateUrls(); // vm.api.urls.credentialMeta();
});
};
vm.api.authn._ropOpts = function () {
//var opts = { email: vm.form.id, uuid: vm.form.otpUuid, code: vm.form.otpCode };
return vm.api.authn._ropOpts_ = {
client_id: vm.conf.client_uid || undefined
, client_uri: vm.conf.client_uri || undefined
, grant_type: 'password'
, username: vm.form.id || undefined
, password: vm.form.otpCode || undefined
, totp: vm.form.totpToken || undefined
, otp: vm.form.otpCode || "{{otp-code}}"
, password_type: vm.form.otpCode && 'otp' || undefined
, otp_code: vm.form.otpCode || undefined
, otp_id: vm.form.otpUuid || undefined
, otp_uuid: vm.form.otpUuid || undefined
, user_agent: navigator.userAgent || undefined // "AJ's Macbook" for a specific device?
, jwk: vm.form.rememberDevice && opts.jwk || undefined
//, "public_key": opts.rememberDevice && opts.publicKey || undefined
//, "public_key_type": opts.rememberDevice && opts.publicKeyType || undefined // RSA/ECDSA
//, "jwt": opts.jwt // TODO sign a proof with a previously loaded public_key
, debug: vm.form.debug || undefined
};
};
vm.api.urls.resourceOwnerPassword = function () {
if (!vm.directives || !vm.form.otpUuid) { return; }
vm.urls.resourceOwnerPassword = OAUTH3.urls.resourceOwnerPassword(vm.directives, vm.api.authn._ropOpts());
};
vm.api.authn.resourceOwnerPassword = function () {
vm.fn.updateUrls(); // vm.api.urls.resourceOwnerPassword();
OAUTH3.authn.resourceOwnerPassword(vm.directives, vm.api.authn._ropOpts()).then(function (resp) {
vm.responses.resourceOwnerPassword = { status: 0, data: resp };
vm.form.accessToken = vm.accessToken = resp.access_token;
vm.form.refreshToken = vm.refreshToken = resp.refresh_token;
vm.ropSession = resp;
vm.ropToken = resp.token;
vm.fn.updateUrls(); // vm.api.urls.resourceOwnerPassword(); also grants
});
};
vm.api.jwt.decode = function () {
vm.ropToken = OAUTH3.jwt.decode(vm.form.accessToken || vm.accessToken);
};
vm.api.jwt.decodeRefresh = function () {
vm.ropToken = OAUTH3.jwt.decode(vm.form.refreshToken || vm.refreshToken);
};
vm.api.providerUri = function () {
console.log('[DEBUG] providerUri:', vm.providerUri);
try {
vm.providerUri = OAUTH3.uri.normalize(vm.providerUri);
vm.conf.provider_uri = vm.providerUri;
} catch(e) {
vm.error = e;
}
};
vm.api.clientUri = function () {
console.log('[DEBUG] clientUri:', vm.clientUri);
try {
vm.clientUri = OAUTH3.clientUri({ host: vm.clientUri });
if (vm.clientUri) {
console.log('[DEBUG] clientUri:', vm.clientUri);
vm.conf.client_uri = vm.clientUri;
vm.conf.client_id = vm.clientUri;
}
} catch(e) {
vm.error = e;
}
};
vm.api._discoverCount = 0;
vm.api.urls.implicitGrant = function (provider) {
if (!vm.directives) {
console.log('[DEBUG] skipping implicit grant due to missing directives');
return;
}
var opts = {
client_uri: vm.conf.client_uri
, subject: vm.form.subject || undefined
, debug: vm.conf.debug || undefined
, scope: vm.form.scopes || undefined
};
var implicitGrantObj = OAUTH3.urls.implicitGrant(vm.directives, opts);
vm.urls.implicitGrant = vm.implicitGrantUrl = (OAUTH3.url.normalize(provider || vm.form.provider) + '/' + implicitGrantObj.url).replace(implicitGrantObj.state, '{{random}}');
}
vm.api.discover = function () {
vm.directives = null;
vm.validated.provider = '';
vm.api._discoverCount += 1;
var latest = vm.api._discoverCount;
var provider = vm.form.provider; // shouldn't be mutable during this time but...
vm.fn.lock();
vm.discoveryObj = OAUTH3.urls.discover(provider, vm.conf);
vm.urls.directives = vm.directivesUrl = OAUTH3.url.normalize(provider) + '/' + vm.discoveryObj.query._pathname;
vm.urls.discovery = vm.discoveryUrl = vm.discoveryObj.method + ' ' + vm.discoveryObj.url;
console.log('about to discover');
return OAUTH3.discover(provider, vm.conf).then(function (dir) {
if (latest !== vm.api._discoverCount) {
console.log('[DEBUG] ignoring stale discover response for', provider);
return;
}
console.log('[DEBUG] directives:');
console.log(dir);
vm.validated.provider = provider;
vm.directives = dir;
vm.api.urls.implicitGrant(provider);
//JSON.stringify(dir, null, 2);
}, function (err) {
vm.form.provider = vm.defaults.provider;
vm.validated.provider = vm.defaults.provider;
vm.directives = vm.defaults.directives;
if (latest !== vm.api._discoverCount) {
console.warn('[DEBUG] ignoring stale discover error for', provider);
console.warn(err);
return;
}
console.log('error on discover');
vm.error = err;
}).then(function () {
vm.fn.unlock();
});
};
vm.api.urls.scope = function () {
// TODO do something like this in the oauth3 library
vm.urls.scope = 'https://:host/.well-known/oauth3/scopes/:scope.json\nhttps://example.com/.well-known/oauth3/scopes/example@oauth3.org.json\n\n'
+ 'GET https://example.com/.well-known/oauth3/#/?action=scope&state={{random}}&redirect_uri=https%3A%2F%2Fsso.hellabit.com%2F.well-known%2Foauth3%2Fcallback.html%23%2F&response_type=rpc&_method=GET&_pathname=.well-known%2Foauth3%2Fscopes%2Fexample@oauth3.org.json';
};
vm.api.discoverScopes = function () {
var scopes = vm.form.scopes && vm.form.scopes.split(',') || [];
vm.scopesObj = [];
function nextScope() {
var scopename = scopes.shift();
if (!scopename) {
return;
}
// something like https://example.com/.well-known/oauth3.org/scopes/:scopename.json
var scopeUrlObj = OAUTH3.urls.discoverScope(vm.form.provider, {
client_uri: vm.conf.client_uri
, scope: scopename
, debug: vm.conf.debug || undefined
});
vm.urls.scope = vm.scopeUrl = OAUTH3.url.normalize(provider) + '/' + scopeUrlObj.query._pathname;
// something like the discovery url that loads in an iframe
var discoverScopeObj = OAUTH3.urls.discoverScope(vm.form.provider, {
client_uri: vm.conf.client_uri
, scope: scopename
, debug: vm.conf.debug || undefined
});
vm.urls.discoverScope = vm.discoverScopeUrl = OAUTH3.url.normalize(provider) + '/' + discoverScopeObj.url;
// Go and fetch!
return OAUTH3.discoverScopes(vm.form.provider, {
client_uri: vm.conf.client_uri
, scope: scopename
, debug: vm.conf.debug || undefined
}).then(function (scope) {
var allScopes = {};
vm.scopesObj.push(scope);
vm.defaults.scopes.push(scope);
vm.defaults.scopes = vm.defaults.scopes.filter(function (scope) {
if (allScopes[scope.name]) {
return false;
}
allScopes[scope.name] = true;
return true;
});
}, function (err) {
console.error("Error in discover scope:");
console.error(err);
vm.scopesObj.push({ name: scopename, desc: "Error, not found" });
});
}
return nextScope();
};
vm.api.implicitGrant = function () {
var provider = vm.validated.provider;
var opts = {
client_uri: vm.conf.client_uri
, subject: vm.form.subject || undefined
, debug: vm.conf.debug || undefined
, scope: vm.form.scopes || undefined
};
console.log('[DEBUG] vm.directives');
console.log(vm.directives);
vm.implicitGrantObj = OAUTH3.urls.implicitGrant(vm.directives, opts);
console.log('[DEBUG] vm.implicitGrantObj');
console.log(vm.implicitGrantObj);
vm.urls.implicitGrant = vm.implicitGrantUrl = (OAUTH3.url.normalize(provider) + '/' + vm.implicitGrantObj.url);
return OAUTH3.implicitGrant(vm.directives, opts).then(function (session) {
vm.session = session;
});
};
vm.urls.profile = {};
vm.api.urls.profile_get = function () {
if (!vm.directives || !vm.accessToken) { return; }
vm.urls.profile_get = OAUTH3.urls.accounts.get(vm.directives, vm.ropSession);
};
vm.api.profile = {};
vm.api.profile_get = function () {
console.log('you tickled me!', vm.ropSession);
vm.api.urls.profile_get();
return OAUTH3.requests.accounts.get(vm.directives, vm.ropSession).then(function (resp) {
console.log('you tickled me twice!');
if (!resp.data) {
resp = { status: 0, data: resp };
}
vm.responses.profile_get = resp;
}, function (err) {
console.error('Could not get profile:');
console.error(err);
vm.error = err;
});
};
vm.api.profile_set = function () {
console.log('you tickled me!', vm.ropSession);
vm.api.urls.profile_set();
return OAUTH3.requests.accounts.set(vm.directives, vm.ropSession).then(function (resp) {
console.log('you tickled me twice!');
if (!resp.data) {
resp = { status: 0, data: resp };
}
vm.responses.profile_set = resp;
}, function (err) {
console.error('Could not set profile:');
console.error(err);
vm.error = err;
});
};
vm.api.authz = {};
vm.api.authz._grantsOpts = function () {
return vm.api.authz._grantsOpts_ = {
method: 'GET'
, client_id: vm.conf.client_id
, client_uri: vm.conf.client_uri
, session: vm.ropSession
, debug: vm.conf.debug
, all: true
};
};
vm.api.urls.grants = function () {
if (!vm.directives || !vm.ropSession || !vm.form.id) { return; }
vm.urls.grants = OAUTH3.urls.grants(vm.directives, vm.api.authz._grantsOpts());
};
vm.api.authz.grants = function () {
vm.fn.updateUrls(); // vm.api.urls.grants();
return OAUTH3.authz.grants(vm.form.provider, vm.api.authz._grantsOpts()).then(function (resp) {
vm.responses.grants = { status: 0, data: resp };
vm.fn.updateUrls(); // vm.api.urls.grants();
}, function (err) {
console.error('[error] authz.grants:');
console.error(err);
vm.error = err;
});
};
vm.form.provider = vm.defaults.provider;
vm.validated.provider = vm.defaults.provider;
vm.api.discover().then(function () {
vm.defaults.directives = vm.directives;
});
vm.fn.updateScopes();
vm.apistr = '';
Object.keys(OAUTH3).forEach(function (key) {
var thingy = OAUTH3[key];
if ('_' === key[0] || -1 !== [ 'create', '_browser', '_defaultStorage', 'hooks', '_hooks', '_digest' ].indexOf(key)) {
return;
}
if ('function' === typeof thingy) {
vm.apistr += thingy.toString().split(/\n/)[0].replace('function ', 'OAUTH3.' + key).replace(/\s+{\s*/, '') + '\n';
}
if ('object' === typeof thingy) {
Object.keys(thingy).forEach(function (key2) {
var thingy2 = thingy[key2];
if ('function' === typeof thingy2) {
vm.apistr += thingy2.toString().split(/\n/)[0].replace('function ', 'OAUTH3.' + key + '.' + key2).replace(/\s+{\s*/, '') + '\n';
}
if ('object' === typeof thingy2) {
Object.keys(thingy2).forEach(function (key3) {
var thingy3 = thingy2[key3];
if ('function' === typeof thingy3) {
vm.apistr += thingy3.toString().split(/\n/)[0].replace('function ', 'OAUTH3.' + key + '.' + key2 + '.' + key3).replace(/\s+{\s*/, '') + '\n';
}
});
}
});
}
});
} ] );
}());

View File

@ -40,21 +40,18 @@ $('body').on('click', '.js-remember-label', function (ev) {
var $this = $(this); var $this = $(this);
if ($this.find('.js-remember-checkbox').is(':checked') === true) { if ($this.find('.js-remember-checkbox').is(':checked') === true) {
$this.find('.js-remember-checkbox').prop( "checked", false ); $this.find('.js-remember-checkbox').prop( "checked", false );
$this.find('.js-remember-status').attr("src", "./img/unpressed-check.png");
} else { } else {
$this.find('.js-remember-checkbox').prop( "checked", true ); $this.find('.js-remember-checkbox').prop( "checked", true );
$this.find('.js-remember-status').attr("src", "./img/pressed-check.png");
} }
}); });
$('body').on('click', '.check', function () {
'use strict';
});
$('body').on('click', '.js-auth-li-enabled', function (ev) { $('body').on('click', '.js-auth-li-enabled', function (ev) {
'use strict'; 'use strict';
ev.preventDefault(); ev.preventDefault();
ev.stopPropagation(); ev.stopPropagation();
var $this = $(this); var $this = $(this);
var $hiddenCheckbox = $this.find('.js-auth-checkbox'); var $hiddenCheckbox = $this.find('.js-auth-checkbox');
var $img = $this.find('.check'); var $img = $this.find('.check');

616
playground.html Normal file
View File

@ -0,0 +1,616 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Login Facilitator: OAuth3.org</title>
<link rel="stylesheet" type="text/css" href="/css/bootstrap.min.css">
<!-- <link rel="stylesheet" type="text/css" href="/css/style.css"> -->
<link rel="stylesheet" type="text/css" href="https://fonts.googleapis.com/css?family=Lato:300">
<script src="https://use.fontawesome.com/3af0faae66.js"></script>
<!-- link rel="stylesheet" type="text/css" href="/css/daplie-installer-overrides.css" -->
</head>
<body>
<div class="fade in js-playground" ng-app="oauth3Playground" ng-strict>
<div ng-controller="PlaygroundCtrl as vm">
<div class="container">
<div class="jumbotron">
<h1>OAuth3 Playground</h1>
</div>
<div class="row">
<div class="col-md-12">
<h2>Go ahead, test our login</h2>
<div ng-if="vm.error" class="alert alert-warning"><span ng-bind="vm.error.message"></span><button class="btn btn-danger pull-right" type="button" ng-click="vm.error = null">X</button></div>
<div ng-if="vm._working" class="alert alert-info">
<marquee>taking my sweet time to do something in the background...</marquee>
</div>
<div ng-if="vm.validated.provider" class="alert alert-success"><span ng-bind="vm.validated.provider"></span> will be used as the login issuer</div>
<label>Address:</label>
<input type="text" placeholder="ex: john@example.com (optional)" class="form-control" ng-model="vm.form.id" ng-change="vm.fn.changeUser()">
<label ng-if="vm.advanced">Identity Issuer:</label>
<input ng-if="vm.advanced" type="text" class="form-control" ng-model="vm.form.provider" placeholder="ex: sso.example.com (required)" ng-change="vm.fn.changeProvider()">
<button class="btn btn-link" ng-if="!vm.advanced" ng-click="vm.fn.toggleAdvanced()">open advanced</button>
<button class="btn btn-link" ng-if="vm.advanced" ng-click="vm.fn.toggleAdvanced()">close advanced</button>
<button class="btn btn-primary" ng-click="vm.api.implicitGrant()" ng-disabled="!vm.validated.provider">Login</button>
<label><input type="checkbox" ng-model="vm.conf.debug" ng-change="vm.fn.updateDebug()"/> Debug OAuth3 Flow?</label>
</div>
</div>
<div class="row">
<div class="col-md-12">
<br/>
<br/>
<br/>
</div>
</div>
<div class="row">
<div class="col-md-12">
<h2>Debug & Status Info:</h2>
</div>
</div>
<div class="row">
<div class="col-md-12">
<h3>JavaScript Framework</h3>
<small>(yes, real runs-in-a-web-browser - and even on Android - ES5.1)</small>
<br>
<label><input name="framework" type="radio" ng-model="vm.framework" ng-value="'none'"/> ES5.1</label> (no framework)
<label><input name="framework" type="radio" ng-model="vm.framework" ng-value="'jquery'"/> jQuery</label>
<label><input name="framework" type="radio" ng-model="vm.framework" ng-value="'angularjs'"/> AngularJS</label>
<label><input name="framework" type="radio" ng-model="vm.framework" ng-value="'nodejs'"/> node.js</label>
<br>
<label><input name="framework" type="checkbox" checked="checked" disabled="disabled"/> azp<small>@oauth3.org</small></label>
<label><input name="framework" type="checkbox" ng-model="vm.components.issuer"/> issuer<small>@oauth3.org</small></label>
<br>
<pre ng-if="'nodejs' === vm.framework"><code>var OAUTH3 = require('oauth3.org');</code></pre>
<pre ng-if="'nodejs' !== vm.framework"><code>&lt;script src="/assets/oauth3.org/oauth3.core.js">&lt;/script><span ng-if="vm.components.issuer">
&lt;script src="/assets/oauth3.org/oauth3.crypto.js">&lt;/script>
&lt;script src="/assets/oauth3.org/oauth3.issuer.js">&lt;/script></span><span
ng-if="'none' === vm.framework || 'jquery' === vm.framework"></span><span ng-if="'angularjs' === vm.framework">
&lt;script src="/assets/oauth3.org/oauth3.ng.js">&lt;/script></span>
</code></pre>
</div>
</div>
<div class="row">
<br>
<br>
<div class="col-md-3">
<strong>Client URI</strong>: <span ng-bind="vm.conf.client_uri"></span>
<br>
(this is the URL of the application as per window.location.href)
</div>
<div class="col-md-9">
<input class="form-input" type="text" ng-model="vm.clientUri">
<button class="btn btn-default" ng-click="vm.api.clientUri()">Set</button>
<pre><code>OAUTH3.clientUri({ host: "<span ng-bind="vm.clientUri"></span>", port: null, pathname: '/' });</code></pre>
</div>
</div>
<div class="row">
<br>
<br>
<div class="col-md-3">
<strong>Subject</strong>: <span ng-bind="vm.form.subject"></span>
<br>
(this is either the subject portion or whole address of subject@issuer)
</div>
<div class="col-md-9">
<input class="form-input" type="text" ng-model="vm.form.id">
<button class="btn btn-default" ng-click="vm.fn.changeUser()">Set</button>
<pre><code>address: <span ng-bind="vm.form.id"></span></code></pre>
<pre><code>subject: <span ng-bind="vm.form.subject"></span></code></pre>
<pre><code>issuer: <span ng-bind="vm.form.userProvider"></span></code></pre>
</div>
</div>
<div class="row" ng-if="vm.validated.provider">
<br>
<br>
<div class="col-md-3">
<strong>Issuer URI</strong>: <span ng-bind="vm.validated.provider"></span>
<br>
(this is the URL part of subject@issuer)
</div>
<div class="col-md-9">
<input class="form-input" type="text" ng-model="vm.form.provider">
<button class="btn btn-default" ng-click="vm.fn.changeProvider()">Set</button>
</div>
</div>
<div class="row" ng-if="vm.validated.provider">
<br>
<br>
<div class="col-md-3">
<strong>Directives Discovery</strong>:
<br>
(this is how we learn if a server support oauth3 and to what extent)
</div>
<div class="col-md-9">
<button class="btn btn-default" ng-click="vm.fn.changeProvider()">Discover Directives</button>
<pre><code>OAUTH3.urls.discover("<span ng-bind="vm.form.provider"></span>", opts);</code></pre>
<pre ng-if="vm.urls.directives"><code><span ng-bind="vm.urls.directives"></span></code></pre>
<pre><code>OAUTH3.discover("<span ng-bind="vm.form.provider"></span>", opts);</code></pre>
<pre ng-if="vm.urls.discovery"><code><span ng-bind="vm.urls.discovery"></span></code></pre>
<div ng-if="vm.directives">
<button ng-if="vm.state.hideDirectives" class="btn btn-link" ng-click="vm.state.hideDirectives = !vm.state.hideDirectives">show directives</button>
<button ng-if="!vm.state.hideDirectives" class="btn btn-link" ng-click="vm.state.hideDirectives = !vm.state.hideDirectives">hide directives</button>
<pre ng-if="!vm.state.hideDirectives"><code><span ng-bind="vm.directives | json"></span></code></pre>
</div>
</div>
</div>
<div class="row">
<br>
<br>
<div class="col-md-3">
<strong>Scopes</strong>: <span ng-bind="vm.form.scopes"></span>
<br>
(these are used to lookup the descriptions of grant permissions)
</div>
<div class="col-md-9">
<input class="form-input" type="text" ng-model="vm.form.scopes" placeholder="ex: authn@oauth3.org,photos@example.com,dns@domains.org">
<button class="btn btn-default" ng-click="vm.api.discoverScopes()" ng-disabled="!vm.form.scopes">Discover Scopes</button>
<ul>
<li ng-repeat="scope in vm.defaults.scopes">
<label>
<input type="checkbox" ng-model="scope.checked" ng-change="vm.fn.updateScopes()"/>
<strong ng-bind="scope.name">name</strong>
</label>
<span ng-bind="scope.desc">desc</span>
</li>
</ul>
<pre><code>OAUTH3.urls.scope(directives, opts);</code></pre>
<pre ng-if="vm.urls.scope"><code><span ng-bind="vm.urls.scope"></span></code></pre>
<pre ng-if="vm.urls.discoverScope"><code><span ng-bind="vm.urls.discoverScope"></span></code></pre>
<pre><code>OAUTH3.discoverScopes(directives, opts);</code></pre>
<button ng-if="vm.scopesObj" class="btn btn-default" ng-click="vm.fn.clearScopes()">[X]</button>
<pre ng-if="vm.scopesObj"><code><span ng-bind="vm.scopesObj | json"></span></code></pre>
</div>
</div>
<div class="row" ng-if="vm.validated.provider">
<br>
<br>
<div class="col-md-3">
<strong>Authorization Dialog URL</strong>
<br>
(this is what opens the login dialog box with the checkboxes and such)
</div>
<div class="col-md-9">
<button class="btn btn-default" ng-click="vm.api.implicitGrant()" ng-disabled="!vm.directives || !vm.validated.provider">Open Authorization Dialog</button>
<pre><code>OAUTH3.urls.implicitGrant(directives, opts);</code></pre>
<pre ng-if="vm.urls.implicitGrant"><code><span ng-bind="vm.urls.implicitGrant"></span></code></pre>
<pre><code>OAUTH3.implicitGrant(directives, opts);</code></pre>
<button ng-if="vm.session" class="btn btn-default" ng-click="vm.fn.clearSession()">[X]</button>
<pre ng-if="vm.session"><code><span ng-bind="vm.session | json"></span></code></pre>
</div>
</div>
<div class="row" ng-if="vm.validated.provider">
<br>
<br>
<div class="col-md-3">
<strong>Refresh Token URL</strong>
<br>
(This is the URL of the iFrame that completes token refreshes. And it occurs over iFrame rather than API so that no server is required.)
</div>
<div class="col-md-9">
<button class="btn btn-default" ng-click="vm.api.refreshToken()" ng-disabled="!vm.directives || !vm.validated.provider">Refresh Token</button>
<pre><code>OAUTH3.urls.refreshToken(directives, opts);</code></pre>
<pre ng-if="vm.urls.refreshToken"><code><span ng-bind="vm.urls.refreshToken"></span></code></pre>
<pre><code>OAUTH3.refreshToken(directives, opts);</code></pre>
</div>
</div>
<div class="row" ng-if="vm.validated.provider">
<br>
<br>
<div class="col-md-3">
<strong>Logout Dialog URL</strong>
<br>
(this is what opens the logout dialog)
</div>
<div class="col-md-9">
<button class="btn btn-default" ng-click="vm.api.logout()" ng-disabled="!vm.directives || !vm.validated.provider">Open Logout Dialog</button>
<pre><code>OAUTH3.urls.logout(directives, opts);</code></pre>
<pre ng-if="vm.urls.logout"><code><span ng-bind="vm.urls.logout"></span></code></pre>
<pre><code>OAUTH3.logout(directives, opts);</code></pre>
</div>
</div>
<div class="row">
<h2>1st Party and App Login</h2>
<br>
<br>
<div class="col-md-3">
<strong>Credential Meta URL</strong>
<br>
<strong>(Not implemented... anymore)</strong>
<br>
(this is the endpoint that reports if the user exists and what their proof-strategy is)
</div>
<div class="col-md-9">
<button class="btn btn-default" ng-click="vm.api.authn.credentialMeta()" ng-disabled="true || !vm.directives || !vm.form.id">Check user details</button>
<pre><code>OAUTH3.authn.loginMeta(directives, { email: "<span ng-bind="vm.form.id"></span>" });</code></pre>
<pre ng-if="vm.urls.credentialMeta"><code><span ng-bind="vm.urls.credentialMeta"></span></code></pre>
<pre ng-if="vm.responses.credentialMeta"><code><span ng-bind="vm.responses.credentialMeta"></span></code></pre>
</div>
</div>
<div class="row" ng-if="vm.validated.provider">
<br>
<br>
<div class="col-md-3">
<strong>Credential OTP URL</strong>
<br>
(this is the URL that sends your one-time password via email)
</div>
<div class="col-md-9">
<button class="btn btn-default" ng-click="vm.api.authn.otp()" ng-disabled="!vm.directives || !vm.form.id">Send OTP to user</button>
<pre><code>OAUTH3.authn.otp(directives, { email: "<span ng-bind="vm.form.id"></span>" });</code></pre>
<div ng-if="vm.urls.otp">
<pre><code><span ng-bind="vm.urls.otp.method"></span> <span ng-bind="vm.urls.otp.url"></span>
<span ng-if="vm.urls.otp.headers" ng-bind="vm.urls.otp.headers | json"></span>
<span ng-bind="vm.urls.otp.data | json"></span>
</code></pre>
<pre ng-if="vm.responses.otp"><code><span ng-bind="vm.responses.otp.status"></span>
<span ng-if="vm.responses.otp.headers" ng-bind="vm.responses.otp.headers | json"></span>
<span ng-bind="vm.responses.otp.data | json"></span>
</code></pre>
</div>
</div>
</div>
<div class="row" ng-if="vm.validated.provider">
<br>
<br>
<div class="col-md-3">
<strong>Resource Owner Password URL</strong>
<br>
(this is the URL that native apps and APIs use to login)
<br>
(it's also a bit of a misnomer, it should be *proof* rather than password)
</div>
<div class="col-md-9">
<input class="form-input" type="text" ng-model="vm.form.otpCode" ng-change="vm.api.urls.resourceOwnerPassword()" placeholder="ex: XXXX-XXXX-XXXX">
<button class="btn btn-default" ng-click="vm.api.authn.resourceOwnerPassword()" ng-disabled="!vm.form.otpUuid || !vm.form.otpCode">Exchange Proof for Session</button>
<br>
<input class="form-input disabled" type="text" ng-model="vm.form.otpUuid" disabled>
<pre><code>OAUTH3.urls.resourceOwnerPassword(directives, opts);</code></pre>
<div ng-if="vm.urls.resourceOwnerPassword">
<pre><code><span ng-bind="vm.urls.resourceOwnerPassword.method"></span> <span ng-bind="vm.urls.resourceOwnerPassword.url"></span>
<span ng-if="vm.urls.resourceOwnerPassword.headers" ng-bind="vm.urls.resourceOwnerPassword.headers | json"></span>
<span ng-bind="vm.urls.resourceOwnerPassword.data | json"></span>
</code></pre>
</div>
<pre><code>OAUTH3.authn.resourceOwnerPassword(directives, <span ng-bind="vm.api.authn._ropOpts_ || 'opts'"></span>);</code></pre>
</div>
</div>
<div class="row" ng-if="vm.validated.provider">
<br>
<br>
<div class="col-md-3">
<strong>Session</strong>
<br>
(this is the object that contains meta data about the session, including the access token itself)
</div>
<div class="col-md-9">
<pre ng-if="vm.responses.resourceOwnerPassword"><code><span ng-bind="vm.responses.resourceOwnerPassword.status"></span>
<span ng-if="vm.responses.resourceOwnerPassword.headers" ng-bind="vm.responses.resourceOwnerPassword.headers | json"></span>
<span ng-bind="vm.responses.resourceOwnerPassword.data | json"></span>
</code></pre>
</div>
</div>
<div class="row" ng-if="vm.validated.provider">
<br>
<br>
<div class="col-md-3">
<strong>Profile</strong>
<br>
(this is the profile object)
</div>
<div class="col-md-9">
<button class="btn btn-default" ng-click="vm.api.profile_get()" ng-disabled="!vm.accessToken">Get Profile</button>
<pre><code><span ng-bind="vm.urls.profile_get.method"></span> <span ng-bind="vm.urls.profile_get.url"></span>
<span ng-if="vm.urls.profile_get.headers" ng-bind="vm.urls.profile_get.headers | json"></span>
<span ng-bind="vm.urls.profile_get.data | json"></span>
</code></pre>
<pre ng-if="!vm.responses.profile_get"><code> ...
</code></pre>
<pre ng-if="vm.responses.profile_get"><code><span ng-bind="vm.responses.profile_get.status"></span>
<span ng-if="vm.responses.profile_get.headers" ng-bind="vm.responses.profile_get.headers | json"></span>
<span ng-bind="vm.responses.profile_get.data | json"></span>
</code></pre>
</div>
</div>
<div class="row" ng-if="vm.validated.provider">
<br>
<br>
<div class="col-md-3">
<strong>Access Token</strong>
<br>
(this is the access token)
</div>
<div class="col-md-9">
<pre><code>OAUTH3.jwt.decode(token);</code></pre>
<textarea class="form-control" ng-model="vm.accessToken" ng-change="vm.api.jwt.decode()"></textarea>
<button class="btn btn-default" ng-click="vm.api.jwt.decode()" ng-disabled="!vm.accessToken">Decode Access Token</button>
<textarea ng-if="vm.refreshToken" class="form-control" ng-model="vm.refreshToken" ng-change="vm.api.jwt.decodeRefresh()"></textarea>
<button ng-if="vm.refreshToken" class="btn btn-default" ng-click="vm.api.jwt.decodeRefresh()" ng-disabled="!vm.refreshToken">Decode Refresh Token</button>
<pre ng-if="vm.ropToken"><code ng-bind="vm.ropToken | json"></code></pre>
</div>
</div>
<div class="row" ng-if="vm.validated.provider">
<br>
<br>
<div class="col-md-3">
<strong>Token Issuer's Public Key</strong>
<br>
<strong>(not implemented)</strong>
<br>
(this is the URL that inspects and verifies the token)
</div>
<div class="col-md-9">
<button class="btn btn-default" ng-click="vm.api.authn.jwk()" ng-disabled="!vm.directives">Fetch Token Issuer's Public Key</button>
<pre><code>OAUTH3.authn.jwk(directives, token);</code></pre>
<div ng-if="vm.urls.jwk">
<pre><code><span ng-bind="vm.urls.jwk.method"></span> <span ng-bind="vm.urls.jwk.url"></span>
<span ng-if="vm.urls.jwk.headers" ng-bind="vm.urls.jwk.headers | json"></span>
<span ng-bind="vm.urls.jwk.data | json"></span>
</code></pre>
<pre ng-if="vm.responses.jwk"><code><span ng-bind="vm.responses.jwk.status"></span>
<span ng-if="vm.responses.jwk.headers" ng-bind="vm.responses.jwk.headers | json"></span>
<span ng-bind="vm.responses.jwk.data | json"></span>
</code></pre>
</div>
</div>
</div>
<div class="row" ng-if="vm.validated.provider">
<br>
<br>
<div class="col-md-3">
<strong>Verify JWT</strong>
<br>
<strong>(not implemented)</strong>
<br>
(ppids can be verified via the public key of the issuer)
</div>
<div class="col-md-9">
<label>JWK</label>
<textarea class="form-control" ng-model="vm.responses.jwk.data"></textarea>
<br>
<label>Access Token</label>
<textarea class="form-control" ng-model="vm.accessToken"></textarea>
<br>
<button class="btn btn-default" ng-click="vm.api.jwt.verify()" ng-disabled="!vm.accessToken || !vm.responses.jwk.data">Verify JWT</button>
<pre><code>OAUTH3.jwt.verify(token, jwk);</code></pre>
<pre><code><span ng-bind="vm.responses.verify"></code></pre>
</div>
</div>
<div class="row" ng-if="vm.validated.provider">
<br>
<br>
<div class="col-md-3">
<strong>Exchange Opaque Token</strong>
<br>
<strong>(not implemented)</strong>
<br>
(Opaque tokens are issued serverside - like a traditional OAuth2 token - and do not contain a subject and, therefore, cannot identify a user directly.
They may be used by multiple audiences client-side, but must be exchanged by authorized parties for a ppid access token to verify identity serverside.
They can be refreshed without changing the JTI.)
</div>
<div class="col-md-9">
<textarea class="form-control" ng-model="vm.form.opaqueToken"></textarea>
<button class="btn btn-default" ng-click="vm.api.authz.exchange()" ng-disabled="!vm.directives || !vm.responses.jwk.data">Exchange Opaque Token</button>
<textarea ng-if="vm.refreshToken" class="form-control" ng-model="vm.refreshToken"></textarea>
<pre><code>OAUTH3.authz.exchange(directives, token);</code></pre>
<div ng-if="vm.urls.exchange">
<pre><code><span ng-bind="vm.urls.exchange.method"></span> <span ng-bind="vm.urls.exchange.url"></span>
<span ng-if="vm.urls.exchange.headers" ng-bind="vm.urls.exchange.headers | json"></span>
<span ng-bind="vm.urls.exchange.data | json"></span>
</code></pre>
<pre ng-if="vm.responses.exchange"><code><span ng-bind="vm.responses.exchange.status"></span>
<span ng-if="vm.responses.exchange.headers" ng-bind="vm.responses.exchange.headers | json"></span>
<span ng-bind="vm.responses.exchange.data | json"></span>
</code></pre>
</div>
</div>
</div>
<div class="row">
<br>
<br>
<div class="col-md-3">
<strong>Approved Apps</strong>
<br>
(these are the public keys generated on remember-me devices and the opaque tokens issued to remember-me-not devices)
</div>
<div class="col-md-9">
<button class="btn btn-default" ng-click="vm.api.authz.grants()" ng-disabled="!vm.form.accessToken">List App Grants</button>
<br>
<pre><code>OAUTH3.urls.grants(directives, opts);</code></pre>
<pre><code>OAUTH3.authz.grants(directives, <span ng-bind="vm.api.authz._grantsOpts_"></span>);</code></pre>
<div ng-if="vm.urls.grants">
<pre><code><span ng-bind="vm.urls.grants.method"></span> <span ng-bind="vm.urls.grants.url"></span>
<span ng-if="vm.urls.grants.headers" ng-bind="vm.urls.grants.headers | json"></span>
<span ng-bind="vm.urls.grants.data | json"></span>
</code></pre>
<pre ng-if="vm.responses.grants"><code><span ng-bind="vm.responses.grants.status"></span>
<span ng-if="vm.responses.grants.headers" ng-bind="vm.responses.grants.headers | json"></span>
<span ng-bind="vm.responses.grants.data | json"></span>
</code></pre>
</div>
...
</div>
</div>
<div class="row">
<div class="col-md-3">
Approved Applications:
</div>
<div class="col-md-9">
...
</div>
</div>
<div class="row">
<div class="col-md-12">
<br/>
<br/>
<br/>
</div>
</div>
<div class="row">
<div class="col-md-12">
<h2>Live API</h2>
<small>these are what's actually on the object</small>
<pre><code ng-bind="vm.apistr"></code></pre>
</div>
</div>
<div class="row">
<div class="col-md-12">
<h2>Docs</h2>
<p>0. Include the Library
<pre><code># Browsers
&lt;script src="oauth3.core.js"&gt;&lt;/script&gt;
var OAUTH3 = window.OAUTH3;
# Node.js
var OAUTH3 = require('oauth3.js').OAUTH3;
</code></pre>
<p>1. Establish the Client ID by its URI
<pre><code># Browsers
var clientUri = OAUTH3.clientUri(window.location); // example.com
# Node.js
var clientUri = OAUTH3.clientUri("https://example.com"); // example.com
</code></pre>
<p>2. Provide promisable storage hooks for saving sessions and caching directives
<pre><code>OAUTH3._hooks = {
directives: {
get: function (providerUri) { ... }
, set: function (providerUri, directives) { ... }
, all: function () { ... }
, clear: function () { ... }
, sessions: {
get: function (providerUri, id) { ... }
, set: function (providerUri, newSession, id) { ... }
, all: function (providerUri) { ... }
, clear: function (providerUri) { ... }
}
};
</code></pre>
SECURITY: The default storage engine is window.sessionStorage. Session storage
should be used for app:// urls and localhost urls and other applications
in which the identity of the app is ephemeral, arbitrary, or not distinct.
<p><h4>3. Check to see if the user already has a session</h4>
<pre><code>OAUTH3.hooks.session.get(providerUri).then(function (session) {
console.log('[DEBUG] session:');
console.log(session);
});
OAUTH3.hooks.session.all().then(function (sessions) {
console.log('[DEBUG] all sessions:');
console.log(sessions);
});
</code></pre>
Note: expired sessions should not be returned and stale sessions should be refreshed
<p>4. Prompt the user for their address and perform the lookup to see if it
has a provider.
<pre><code>var providerUri = address.split('@')[1] || address;
var opts = { client_uri: clientUri };
OAUTH3.discover(providerUri, opts).then(function (dir) {
console.log('[DEBUG] directives:');
console.log(dir);
});
</code></pre>
<p>4.
<pre><code>
</code></pre>
</div>
</div>
</div>
</div>
</div>
<!--[if IE]><script src="bower_components/rsvp.js/rsvp.js"></script><![endif]-->
<script src="./js/jquery-2.2.0.min.js"></script>
<script src="/assets/oauth3.org/oauth3.core.js"></script>
<script src="/assets/oauth3.org/oauth3.crypto.js"></script>
<script src="/assets/oauth3.org/oauth3.issuer.js"></script>
<script src="./js/angular-1.6.6.js"></script>
<script src="./js/angular-ui-router-1.0.10.js"></script>
<script src="/assets/oauth3.org/oauth3.ng.js"></script>
<script src="./js/playground.js"></script>
</body>
</html>