Compare commits
26 Commits
master
...
playground
Author | SHA1 | Date |
---|---|---|
AJ ONeal | 8555d3673a | |
AJ ONeal | ff50c74a56 | |
AJ ONeal | 9760bcf6c1 | |
AJ ONeal | c90fd2a6f4 | |
AJ ONeal | f069314e76 | |
AJ ONeal | 0727c3a6c9 | |
AJ ONeal | 242c0e3abb | |
AJ ONeal | ece06b8463 | |
AJ ONeal | 980895992a | |
AJ ONeal | 9aaabeb908 | |
AJ ONeal | 4ab4ad0ac0 | |
AJ ONeal | 0ff3a2e3ce | |
AJ ONeal | 4b6a8f7316 | |
AJ ONeal | 998c652969 | |
drewwarren | 87820b3d24 | |
AJ ONeal | db261147c2 | |
AJ ONeal | 6eb5ea0f3d | |
John Shaver | 23318c01f0 | |
John Shaver | ed1c3374dd | |
John Shaver | 9dbc2b5664 | |
AJ ONeal | 84a8090d49 | |
AJ ONeal | 6105637cc5 | |
AJ ONeal | c5cc2be470 | |
AJ ONeal | a16fbdd764 | |
AJ ONeal | 23765a97ef | |
AJ ONeal | 2500711b8c |
|
@ -0,0 +1 @@
|
||||||
|
_apis
|
|
@ -5,7 +5,7 @@ issuer.html
|
||||||
| *issuer.html*
|
| *issuer.html*
|
||||||
| [issuer.rest.walnut.js](https://git.oauth3.org/OAuth3/issuer.rest.walnut.js)
|
| [issuer.rest.walnut.js](https://git.oauth3.org/OAuth3/issuer.rest.walnut.js)
|
||||||
| [issuer.srv](https://git.oauth3.org/OAuth3/issuer.srv)
|
| [issuer.srv](https://git.oauth3.org/OAuth3/issuer.srv)
|
||||||
| Sponsored by [ppl](https://ppl.family)
|
| Sponsored by [Daplie](https://daplie.com)
|
||||||
|
|
||||||
|
|
||||||
This is a browser application which implements the issuer side of the *authorization_dialog* flow for OAuth3.
|
This is a browser application which implements the issuer side of the *authorization_dialog* flow for OAuth3.
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
oauth3.org
|
|
@ -0,0 +1 @@
|
||||||
|
oauth3.org
|
115
index.html
115
index.html
|
@ -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,58 +142,75 @@
|
||||||
</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>
|
||||||
|
<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 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">
|
|
||||||
<div class="col-md-3">
|
|
||||||
Approved Devices:
|
|
||||||
</div>
|
|
||||||
<div class="col-md-9">
|
|
||||||
...
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-3">
|
|
||||||
Approved Applications:
|
|
||||||
</div>
|
|
||||||
<div class="col-md-9">
|
|
||||||
...
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
<li>Private, Anonymous (Escrow / Broker model)
|
||||||
|
<!--
|
||||||
|
(Escrow / Broker model)
|
||||||
|
When you want transactions to be both private and anonymous there
|
||||||
|
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
|
||||||
|
between two untrusted participants, <em>any</em> OAuth3 Issuer can broker identity and
|
||||||
|
privilege transactions between two parties.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<li>Peer-to-Peer, Anonymous (Public Ledger model)
|
||||||
|
<!--
|
||||||
|
-->
|
||||||
|
</ul>
|
||||||
|
</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>
|
||||||
|
|
||||||
|
|
||||||
<!--[if IE]><script src="bower_components/rsvp.js/rsvp.js"></script><![endif]-->
|
<!--[if IE]><script src="bower_components/rsvp.js/rsvp.js"></script><![endif]-->
|
||||||
<script src="./js/jquery-2.2.0.min.js"></script>
|
<script src="./js/jquery-2.2.0.min.js"></script>
|
||||||
<script src="./js/jquery.mask.min.js"></script>
|
<script src="./js/jquery.mask.min.js"></script>
|
||||||
<script src="./js/bootstrap.min.js"></script>
|
<script src="./js/bootstrap.min.js"></script>
|
||||||
<script src="/assets/oauth3.org/oauth3.core.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.crypto.js"></script>
|
||||||
<script src="/assets/oauth3.org/oauth3.issuer.js"></script>
|
<script src="/assets/oauth3.org/oauth3.issuer.js"></script>
|
||||||
<script src="./js/issuer.js"></script>
|
<script src="./js/issuer.js"></script>
|
||||||
<script src="./js/script.js"></script>
|
<script src="./js/script.js"></script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
18
js/issuer.js
18
js/issuer.js
|
@ -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();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -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';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} ] );
|
||||||
|
}());
|
|
@ -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');
|
||||||
|
|
|
@ -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><script src="/assets/oauth3.org/oauth3.core.js"></script><span ng-if="vm.components.issuer">
|
||||||
|
<script src="/assets/oauth3.org/oauth3.crypto.js"></script>
|
||||||
|
<script src="/assets/oauth3.org/oauth3.issuer.js"></script></span><span
|
||||||
|
ng-if="'none' === vm.framework || 'jquery' === vm.framework"></span><span ng-if="'angularjs' === vm.framework">
|
||||||
|
<script src="/assets/oauth3.org/oauth3.ng.js"></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
|
||||||
|
<script src="oauth3.core.js"></script>
|
||||||
|
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>
|
Loading…
Reference in New Issue