npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

oauth3.js

v1.2.5

Published

The world's smallest, fastest, and most secure OAuth3 (and OAuth2) JavaScript implementation.

Downloads

11

Readme

oauth3.js

| oauth3.js | issuer.html | issuer.rest.walnut.js | issuer.srv | Sponsored by ppl

The world's smallest, fastest, and most secure OAuth3 (and OAuth2) JavaScript implementation (Yes! works in browsers and node.js with no extra dependencies or bloat and no hacks!)

Instead of bloating your webapp and ruining the mobile experience, you can use a single, small javascript file for all OAuth3 providers (and almost all OAuth2 providers) with a seamless experience.

Also, instead of complicated (or worse - insecure) CLI and Desktop login methods, you can easily integrate an OAuth3 flow (or broker) into any node.js app (i.e. Electron, Node-Webkit) with 0 pain.

If you have no idea what you're doing

(people who know what they're doing should skip ahead to the tl;dr instructions)

  1. Create a folder for your project named after your app, such as example.com/
  2. Inside of the folder example.com/ a folder called assets/
  3. Inside of the folder example.com/assets a folder called oauth3.org/
  4. Download oauth3.js-v1.zip
  5. Double-click to unzip the folder.
  6. Copy the file oauth3.core.js into the folder example.com/assets/oauth3.org/
  7. Copy the folder _apis into the folder example.com/
  8. Add <script src="assets/oauth3.org/oauth3.core.js"></script> to your index.html
  9. Add <script src="app.js"></script> to your index.html
  10. Create files in example.com called app.js and index.html and put this in it:

index.html:

<!DOCTYPE html>
<html>
<head>
</head>
<body>

  <input type="url" placeholder="ex: https://oauth3.org" class="js-provider-uri">
  <button type="button" class="js-login">Login</button>
  <button type="button" class="js-logout">Logout</button>

  <script src="https://code.jquery.com/jquery-3.1.1.js"
    integrity="sha256-16cdPddA6VdVInumRGo6IbivbERE8p7CQR3HzTBuELA="
    crossorigin="anonymous"></script>
  <script src="assets/oauth3.org/oauth3.core.js"></script>
  <script src="app.js"></script>
</body>
</html>

app.js:

var OAUTH3 = window.OAUTH3;
var auth = OAUTH3.create(window.location); // use window.location to set Client URI (your app's id)


// this is any OAuth3-compatible provider, such as oauth3.org
// in v1.1.0 we'll add backwards compatibility for facebook.com, google.com, etc
//
function onChangeProvider(_providerUri) {
  // example https://oauth3.org
  return oauth3.setIdentityProvider(providerUri);
}


// This opens up the login window for the specified provider
//
function onClickLogin() {

  return oauth3.authenticate().then(function (session) {

    console.info('Authentication was Successful:');
    console.log(session);

    // You can use the PPID (or preferably a hash of it) as the login for your app
    // (it securely functions as both username and password which is known only by your app)
    // If you use a hash of it as an ID, you can also use the PPID itself as a decryption key
    //
    console.info('Secure PPID (aka subject):', session.token.sub);

    return oauth3.request({
      url: 'https://oauth3.org/api/[email protected]/inspect'
    , session: session
    }).then(function (resp) {

      console.info("Inspect Token:");
      console.log(resp.data);

    });

  }, function (err) {
    console.error('Authentication Failed:');
    console.log(err);
  });

}


// This opens up the logout window
//
function onClickLogout() {

  return oauth3.logout().then(function () {
    localStorage.clear();

    console.info('Logout was Successful');

  }, function (err) {
    console.error('Logout Failed:');
    console.log(err);
  });

}


// initialize the provider to be oauth3.org (or any compatible provider)
//
onChangeProvider('oauth3.org');


$('body').on('click', '.js-login', onClickLogin);
$('body').on('click', '.js-logout', onClickLogout);
$('body').on('change', 'input.js-provider-uri', onChangeProvider);

Copy the example.com/ folder to your webserver.

Example

If you had a simple website / webapp for example.com with only the most necessary files, it might look like this:

example.com
│
│
├── _apis
│   └── oauth3.org
│       ├── callback.html
│       ├── directives.json
│       └── index.html
├── assets
│   └── oauth3.org
│       └── oauth3.core.js
│
│
├── css
│   └── main.css
├── index.html
└── js
    └── app.js

Installation (if you know what you're doing)

Advanced Installation with git

# Navigate to your web site or web app
pushd /path/to/your/web/app


# clone the project as assets/oauth3.org
mkdir -p assets
git clone [email protected]:OAuth3/oauth3.js.git assets/oauth3.org
pushd assets/oauth3.org
git checkout v1
popd


# symlink `_apis/oauth3.org` to `assets/oauth3.org/_apis/oauth3.org`
mkdir -p _apis
ln -sf  ../assets/oauth3.org/_apis/oauth3 _apis/oauth3.org

Advanced Installation with bower

# Install to bower_components
bower install oauth3


# create a `_apis` folder and an `assets` folder
mkdir -p _apis assets


# symlink `_apis/oauth3.org` to `bower_components/oauth3.org/_apis/oauth3.org`
ln -sf  ../bower_components/oauth3.org/_apis/oauth3.org _apis/oauth3.org


# symlink `assets/oauth3.org` to `bower_components/oauth3.org`
ln -sf  ../bower_components/oauth3.org/_apis/oauth3.org _apis/oauth3.org
ln -sf  ../bower_components/oauth3.org assets/oauth3.org

Usage

Update your HTML to include the the following script tag:

<script src="assets/oauth3.org/oauth3.core.js"></script>

You can create a very simple demo application like this:

var providerUri;
var opts = { client_uri: OAUTH3.utils.clientUri(window.location) };


// this is any OAuth3-compatible provider, such as oauth3.org
// in v1.1.0 we'll add backwards compatibility for facebook.com, google.com, etc
//
function onChangeProvider(_providerUri) {
  providerUri = _providerUri;
  return OAUTH3.discover(providerUri, opts); // just to cache
}


// This opens up the login window for the specified provider
//
function onClickLogin() {

  return OAUTH3.implicitGrant(providerUri, opts).then(function (session) {

    console.info('Authentication was Successful:');
    console.log(session);

    // You can use the PPID (or preferably a hash of it) as the login for your app
    // (it securely functions as both username and password which is known only by your app)
    // If you use a hash of it as an ID, you can also use the PPID itself as a decryption key
    //
    console.info('Secure PPID (aka subject):', session.token.sub);

    return OAUTH3.request({
      url: 'https://oauth3.org/api/[email protected]/inspect_token'
    , session: session
    }).then(function (resp) {

      console.info("Inspect Token:");
      console.log(resp.data);

    });

  }, function (err) {
    console.error('Authentication Failed:');
    console.log(err);
  });

}

// initialize the provider to be oauth3.org (or any compatible provider)
//
onChangeProvider('oauth3.org');

A user's e-mail can be passed into the clientParams object as clientParams.subject.

To auto-populate the e-mail input of the login popup, make sure the input has the class js-oauth3-email.

Example:

if (clientParams.subject) {
        $('.js-oauth3-email').val(clientParams.subject);
        $('.js-authn-show').prop('disabled', false);
      }

Compatibility with Frameworks and Libraries

jQuery:

You're all set. Nothing else is needed.

Angular 1:

We've created an Oauth3 service just for you:

<script src="assets/oauth3.org/oauth3.ng.js"></script>
// Require the module as 'oauth3.org'
var app = angular.module('myAppName', [ 'ui.router', 'oauth3.org' ]);

// Require services and other submodules in the form {modulename}@oauth3.org
app.controller('authCtrl', [ '$scope', '[email protected]', function ($scope, Oauth3) { /* ... */ } ]);

// For backwards compatibility with older angular applications that rely on string-name introspection
// you can also use the camel case version of the names in the format {Modulename}Oauth3
app.controller('authCtrl', function ($scope, AzpOauth3) { /* ... */ });

You can include that in addition to the standard file or, if you don't want an extra request, just paste it into your app.js.

Simple API

We include a small wrapper function of just a few lines in the bottom of oauth3.core.js which exposes a create method to make using the underlying library require typing fewer keystrokes.

oauth3 = OAUTH3.create(location);                   // takes a location object, such as window.location
                                                    // to create the Client URI (your app's id)
                                                    // and save it to an internal state

promise = oauth3.init(opts);                        // set and fetch your own site/app's configuration details
// promises your site's config                      // opts = { location, session, issuer, audience }

promise = oauth3.setIdentityProvider(url);          // changes the Identity Provider URI (the site you're logging into),
// promises the provider's config                   // gets the config for that site (from their _apis/oauth3.org),
                                                    // and caches it in internal state as the default

promise = oauth3.setResourceProvider(url);          // changes the Resource Provider URI (the site you're getting stuff from)

promise = oauth3.setProvider(url);                  // changes the both Identity and Resource Provider URI together

promise = oauth3.authenticate();                    // opens login window for the provider and returns a session
                                                    // (must be called after the setIdentityProvider promise has completed)

promise = oauth3.authorize(permissions);            // authenticates (if not authenticated) and opens a window to
                                                    // authorize a particular scope (contacts, photos, whatever)

promise = oauth3.request({ url, method, data });    // make an (authorized) arbitrary request to an audience's resource
                                                    // (contacts, photos, whatever)

promise = oauth3.api(apiname, opts);                // make an (authorized) well-known api call to an audience
                                                    // Ex: oauth3.api('dns.list', { sld: 'example', tld: 'com' });

// TODO
api = await oauth3.package(audience, schemaname);   // make an (authorized) well-known api call to an audience
                                                    // Ex: api = await oauth3.package('domains.example.com', '[email protected]');
                                                    //     api.list({ sld: 'mydomain', tld: 'com' });


promise = oauth3.logout();                          // opens logout window for the provider

oauth3.session();                                   // returns the current session, if any
OAUTH3.clientUri(window.location);                          // produces the default `client_uri` of your app (also used as `client_id`)

OAUTH3.discover(providerUri, { client_id: clientUri });     // Promises the config file for the provider and caches it in memory.

OAUTH3.implicitGrant(providerUri, { client_id: clientUri }) // returns a `session` with `session.token.sub` as the secure ppid.
  // debug: true - will cause the windows to not refresh automatically
  // windowType: 'popup' - will use a popup window to ask user for new permissions, if any
  // windowType: 'background' - will automatically log the user in (if all permissions have been accepted)

OAUTH3.request({ method: 'GET', url: '', session: '', data: '' })       // make an authenticated request to a resource

OAUTH3.logout(providerUri, { client_id: clientUri, session: session })  // opens a popup to confirm logout from the provider
  // Note: you should probably clear your own storage (i.e. localStorage, indexedDb) whenever you call this

OAUTH3.urls
  .discover(providerUri, { client_id: clientUri })          // generates a correctly parameterized url
  .implicitGrant(directives, { client_id: clientUri })      // generates a correctly parameterized url
  .refreshToken(directives, opts)                           // generates a correctly parameterized url
      // opts.client_id = clientUri
      // opts.access_token = <jwt>
      // opts.refresh_token = <jwt>

Core API (staging)

These APIs are NOT yet public, stable APIs, but they are good to be aware of and may help with debugging.

DO NOT rely on them. Many of them WILL change (we just wanted to publish with things as they are).

Public utilities for browser and node.js:

OAUTH3.jwt
  .decode('<urlSafeBase64-encoded-json-web-token>');          // { iat, iss, aud, sub, exp, ttl }

OAUTH3
  .query.stringify({ access_token: '...', debug: true });     // access_token=...&debug=true
  .scope.stringify([ 'profile', 'contacts' ]);                // 'profile,contacts'
  .uri.normalize('https://oauth3.org/connect/');              // 'oauth3.org/connect'
  .url.normalize('oauth3.org/connect/');                      // 'https://oauth3.org/connect'
  .url.resolve('oauth3.org/connect/', '/api/');               // 'https://oauth3.org/connect/api'

Issuer API (staging)

These additional methods are

OAUTH3
  .query.parse('#/?foo=bar&baz=qux');                         // { access_token: '...', debug: 'true' }
  .scope.parse('profile,contacts');                           // [ 'profile', 'contacts' ]
  .url.redirect(clientParams, grants, tokenOrError);          // securely redirect to client (or give security or other error)

Internal API

This APIs will absolutely change before they are made public (at the very least the leading _ will be removed)

OAUTH3.jwt
  .freshness(tokenMeta, staletimeSeconds, _now);        // returns 'fresh', 'stale', or 'expired' (by seconds before expiry / ttl)

OAUTH3
  .url._normalizePath('oauth3.org/connect/');           // 'oauth3.org/connect'
  .randomState();                                       // a 128-bit crypto-random string
  ._insecureRandomState();                              // a fallback for randomState() in old browsers
  ._base64.atob('<non-urlsafe-base64-string>');         // '<binary-string>' (typically json ascii)
  ._base64.decodeUrlSafe(b64);                          // makes base64 safe for window.atob and then calls atob

OAUTH3._browser                                         // a collection of things a browser needs to perform requests

Roadmap

  • v1.0 - "implicit grant" authorization with examples
    • popup
    • iframe
    • documentation
  • v1.1 - cleanup
    • in-flow discovery
    • smallest possible size
    • inline windowing (non-promisable callback)
    • async set/get
    • logout
  • v1.2 - features
    • "authorization code" flow
    • "broker" flow
  • v1.3 - features
    • remove grants

URL generation:

  • authorizationCode
  • authorizationRedirect
  • implicitGrant
  • loginCode
  • resourceOwnerPassword

URI vs URL

See https://danielmiessler.com/study/url-uri/#gs.=MngfAk

Since we do not require the protocol to be specified, it is a URI

However, we do have a problem of disambiguation since a URI may look like a path:

  1. https://example.com/api/[email protected]
  2. example.com/api/[email protected]/ (not unique)
  3. /api/[email protected]
  4. api/[email protected] (not unique)

Therefore anywhere a URI or a Path could be used, the URI must be a URL. We eliminate #2.

As a general rule I don't like rules that sometimes apply and sometimes don't, so I may need to rethink this. However, there are cases where including the protocol can be very ugly and confusing and we definitely need to allow relative paths.

A potential work-around would be to assume all paths are relative (eliminate #4 instead) and have the path always key off of the base URL - if oauth3 directives are to be found at https://example.com/username/_apis/oauth3.org/index.json then /api/whatever would refer to https://example.com/username/api/whatever.