oauth3.js ========= The world's smallest, fastest, and most secure OAuth3 (and OAuth2) JavaScript implementation (Yes! works in browsers and node.js with no extra dependencies or bloat and no hacks!) Instead of bloating your webapp and ruining the mobile experience, you can use a single, small javascript file for all OAuth3 providers (and almost all OAuth2 providers) with a 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](https://git.daplie.com/OAuth3/oauth3.js/repository/archive.zip?ref=v1) 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 `well-known` into the folder `example.com/` 8. Rename the folder `well-known` to `.well-known` (when you do this, it become invisible, that's okay) 9. Add `` to your `index.html` 9. Add `` to your `index.html` 10. Create files in `example.com` called `app.js` and `index.html` and put this in it: `index.html`: ```html
``` `app.js`: ```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/issuer@oauth3.org/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 │ │ ├── .well-known (hidden) │ └── oauth3 │ ├── callback.html │ ├── directives.json │ └── index.html ├── assets │ └── org.oauth3 │ └── oauth3.core.js │ │ ├── css │ └── main.css ├── index.html └── js └── app.js ``` Installation (if you know what you're doing) ------------ **Advanced Installation with `git`** ```bash # Navigate to your web site or web app pushd /path/to/your/web/app # clone the project as assets/org.oauth3 mkdir -p assets git clone git@git.daplie.com:OAuth3/oauth3.js.git assets/org.oauth3 pushd assets/org.oauth3 git checkout v1 popd # symlink `.well-known/oauth3` to `assets/org.oauth3/.well-known/oauth3` mkdir -p .well-known ln -sf ../assets/org.oauth3/.well-known/oauth3 .well-known/oauth3 ``` **Advanced Installation with `bower`** ```bash # Install to bower_components bower install oauth3 # create a `.well-known` folder and an `assets` folder mkdir -p .well-known assets # symlink `.well-known/oauth3` to `bower_components/oauth3/.well-known/oauth3` ln -sf ../bower_components/oauth3/.well-known/oauth3 .well-known/oauth3 # symlink `assets/org.oauth3` to `bower_components/oauth3` ln -sf ../bower_components/oauth3/.well-known/oauth3 .well-known/oauth3 ln -sf ../bower_components/oauth3 assets/org.oauth3 ``` Usage ----- Update your HTML to include the the following script tag: ```html ``` You can create a very simple demo application like this: ```javascript 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/issuer@oauth3.org/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: ```js 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: ```html ``` ```js // 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', 'azp@oauth3.org', 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 .well-known/oauth3), // 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 // See https://labs.daplie.com/docs/ for API schemas // Ex: oauth3.api('dns.list', { sld: 'daplie', 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.daplie.com', 'dns@oauth3.org'); // api.list({ sld: 'mydomain', tld: 'com' }); promise = oauth3.logout(); // opens logout window for the provider oauth3.session(); // returns the current session, if any ``` Real API ---------- ``` 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 =