add intro page, split playground
This commit is contained in:
		
							parent
							
								
									9aaabeb908
								
							
						
					
					
						commit
						980895992a
					
				
							
								
								
									
										584
									
								
								index.html
									
									
									
									
									
								
							
							
						
						
									
										584
									
								
								index.html
									
									
									
									
									
								
							| @ -143,543 +143,52 @@ | |||||||
|   </div> |   </div> | ||||||
| 
 | 
 | ||||||
|   <div class="fade js-playground" ng-app="oauth3Playground" ng-strict> |   <div class="fade js-playground" ng-app="oauth3Playground" ng-strict> | ||||||
|     <div ng-controller="PlaygroundCtrl as vm"> |     <div class="container"> | ||||||
|       <div class="container"> |       <div class="jumbotron"> | ||||||
|         <div class="jumbotron"> |         <h1>OAuth3</h1> | ||||||
|           <h1>OAuth3 Playground</h1> |         <p>A (mostly) client-side authentication and authorization framework for decentralized peer-to-peer and federated networks. | ||||||
|         </div> |       </div> | ||||||
| 
 |       <div class="row"> | ||||||
|         <div class="row"> |         <a class="btn btn-primary" href="playground.html">Enter the OAuth3 Playground</a> | ||||||
|           <div class="col-md-12"> | 
 | ||||||
|             <h2>Go ahead, test our login</h2> |         <div> | ||||||
| 
 |           <h2>Private, Peer-to-Peer, Anonymous: Pick any two... at a time</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> |           <ul> | ||||||
|             <div ng-if="vm._working" class="alert alert-info"> |             <li>Privacy | ||||||
|               <marquee>taking my sweet time to do something in the background...</marquee> |             <li>Peer-to-Peer | ||||||
|             </div> |             <li>Anonymity | ||||||
|             <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> |           </ul> | ||||||
| 
 |           <p>OAuth3's federated design allows it to work in all 3 modes of decentralization: | ||||||
|             <label>Address:</label> |           <ul> | ||||||
|             <input type="text" placeholder="ex: john@example.com (optional)" class="form-control" ng-model="vm.form.id" ng-change="vm.fn.changeUser()"> |             <li>Private, Peer-to-Peer (Trusted model) | ||||||
|             <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()"> |               (Public / Private Keypair model) | ||||||
|             <button class="btn btn-link" ng-if="!vm.advanced" ng-click="vm.fn.toggleAdvanced()">open advanced</button> |               For trusted parties OAuth3 defines how to exchange public keys on the client-side to | ||||||
|             <button class="btn btn-link" ng-if="vm.advanced" ng-click="vm.fn.toggleAdvanced()">close advanced</button> |               ensure that a resource owner's assets can be retrieved, without any involved. | ||||||
|             <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> |             <li>Private, Anonymous (Escrow / Broker model) | ||||||
|         </div> |               <!-- | ||||||
| 
 |               (Escrow / Broker model) | ||||||
|         <div class="row"> |               When you want transactions to be both private and anonymous there | ||||||
|           <div class="col-md-12"> |               must be a mutual trusted authority to broker the transaction to ensure privacy without | ||||||
|             <br/> |               disclosing identity. In the same way that a private escrow service can ensure a valid | ||||||
|             <br/> |               between two untrusted participants, <em>any</em> OAuth3 Issuer can broker identity and | ||||||
|             <br/> |               privilege transactions between two parties. | ||||||
|           </div> |               --> | ||||||
|         </div> | 
 | ||||||
| 
 |             <li>Peer-to-Peer, Anonymous (Public Ledger model) | ||||||
|         <div class="row"> |               <!-- | ||||||
|           <div class="col-md-12"> |               --> | ||||||
| 
 |           </ul> | ||||||
|             <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> |  | ||||||
| 
 |  | ||||||
|                 <button ng-if="vm.directives" class="btn btn-default" ng-click="vm.fn.clearDirectives()">[X]</button> |  | ||||||
|                 <pre ng-if="vm.directives"><code><span ng-bind="vm.directives | json"></span></code></pre> |  | ||||||
|               </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>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.authn.resourceOwnerPassword(directives, <span ng-bind="vm.api.authn._ropOpts_ || 'opts'"></span>);</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> |  | ||||||
|               </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>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.refreshToken">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.directives || !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> |  | ||||||
| 
 |  | ||||||
|             <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> |  | ||||||
|         </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> | ||||||
| 
 | 
 | ||||||
|  |         <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> |   </div> | ||||||
| @ -695,10 +204,5 @@ | |||||||
|   <script src="./js/issuer.js"></script> |   <script src="./js/issuer.js"></script> | ||||||
|   <script src="./js/script.js"></script> |   <script src="./js/script.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> |   </body> | ||||||
| </html> | </html> | ||||||
|  | |||||||
| @ -27,7 +27,7 @@ | |||||||
| 		var vm = this; | 		var vm = this; | ||||||
| 
 | 
 | ||||||
|     vm.framework = 'none'; |     vm.framework = 'none'; | ||||||
|     vm.clientUri = OAUTH3.clientUri(window.location); |     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.conf = { debug: undefined, client_id: vm.clientUri, client_uri: vm.clientUri, provider_uri: vm.clientUri }; | ||||||
|     vm.providerUri = vm.conf.client_uri; |     vm.providerUri = vm.conf.client_uri; | ||||||
|     // map of things being debounced presently
 |     // map of things being debounced presently
 | ||||||
|  | |||||||
							
								
								
									
										585
									
								
								playground.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										585
									
								
								playground.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,585 @@ | |||||||
|  | <!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> | ||||||
|  | 
 | ||||||
|  |             <button ng-if="vm.directives" class="btn btn-default" ng-click="vm.fn.clearDirectives()">[X]</button> | ||||||
|  |             <pre ng-if="vm.directives"><code><span ng-bind="vm.directives | json"></span></code></pre> | ||||||
|  |           </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">Open Logout Dialog</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>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.refreshToken">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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user