(function (exports) { 'use strict'; // NOTE: we assume that directive.provider_uri exists var core = {}; core.stringifyscope = function (scope) { if (Array.isArray(scope)) { scope = scope.join(' '); } return scope; }; core.querystringify = function (params) { var qs = []; Object.keys(params).forEach(function (key) { if ('scope' === key) { params[key] = core.stringifyscope(params[key]); } qs.push(encodeURIComponent(key) + '=' + encodeURIComponent(params[key])); }); return qs.join('&'); }; core.authorizationCode = function (/*directive, scope, redirectUri, clientId*/) { // // Example Authorization Code Request // (not for use in the browser) // // GET https://example.com/api/org.oauth3.provider/authorization_dialog // ?response_type=code // &scope=`encodeURIComponent('profile.login profile.email')` // &state=`Math.random()` // &client_id=xxxxxxxxxxx // &redirect_uri=`encodeURIComponent('https://myapp.com/oauth3.html')` // // NOTE: `redirect_uri` itself may also contain URI-encoded components // // NOTE: This probably shouldn't be done in the browser because the server // needs to initiate the state. If it is done in a browser, the browser // should probably request 'state' from the server beforehand // throw new Error("not implemented"); }; core.authorizationRedirect = function (directive, authorizationRedirect, opts) { //console.log('[authorizationRedirect]'); // // Example Authorization Redirect - from Browser to Consumer API // (for generating a session securely on your own server) // // i.e. GET https://<>.com/api/org.oauth3.consumer/authorization_redirect/<>.com // // GET https://myapp.com/api/org.oauth3.consumer/authorization_redirect/`encodeURIComponent('example.com')` // &scope=`encodeURIComponent('profile.login profile.email')` // // (optional) // &state=`Math.random()` // &redirect_uri=`encodeURIComponent('https://myapp.com/oauth3.html')` // // NOTE: This is not a request sent to the provider, but rather a request sent to the // consumer (your own API) which then sets some state and redirects. // This will initiate the `authorization_code` request on your server // opts = opts || {}; var scope = opts.scope || directive.authn_scope; var providerUri = directive.provider_uri; var state = Math.random().toString().replace(/^0\./, ''); var params = {}; var slimProviderUri = encodeURIComponent(providerUri.replace(/^(https?|spdy):\/\//, '')); params.state = state; if (scope) { params.scope = scope; } if (opts.redirectUri) { // this is really only for debugging params.redirect_uri = opts.redirectUri; } // Note: the type check is necessary because we allow 'true' // as an automatic mechanism when it isn't necessary to specify if ('string' !== typeof authorizationRedirect) { // TODO oauth3.json for self? authorizationRedirect = 'https://' + window.location.host + '/api/org.oauth3.consumer/authorization_redirect/:provider_uri'; } authorizationRedirect = authorizationRedirect .replace(/!(provider_uri)/, slimProviderUri) .replace(/:provider_uri/, slimProviderUri) .replace(/#{provider_uri}/, slimProviderUri) .replace(/{{provider_uri}}/, slimProviderUri) ; return { url: authorizationRedirect + '?' + core.querystringify(params) , method: 'GET' , state: state // this becomes browser_state , params: params // includes scope, final redirect_uri? }; }; core.implicitGrant = function (directive, opts) { //console.log('[implicitGrant]'); // // Example Implicit Grant Request // (for generating a browser-only session, not a session on your server) // // GET https://example.com/api/org.oauth3.provider/authorization_dialog // ?response_type=token // &scope=`encodeURIComponent('profile.login profile.email')` // &state=`Math.random()` // &client_id=xxxxxxxxxxx // &redirect_uri=`encodeURIComponent('https://myapp.com/oauth3.html')` // // NOTE: `redirect_uri` itself may also contain URI-encoded components // opts = opts || {}; var type = 'authorization_dialog'; var responseType = 'token'; var redirectUri = opts.redirectUri; var scope = opts.scope || directive.authn_scope; var clientId = opts.appId; var args = directive[type]; var uri = args.url; var state = Math.random().toString().replace(/^0\./, ''); var params = {}; var loc; var result; params.state = state; params.response_type = responseType; if (scope) { if (Array.isArray(scope)) { scope = scope.join(' '); } params.scope = scope; } if (clientId) { // In OAuth3 client_id is optional for implicit grant params.client_id = clientId; } if (!redirectUri) { loc = window.location; redirectUri = loc.protocol + '//' + loc.host + loc.pathname; if ('/' !== redirectUri[redirectUri.length - 1]) { redirectUri += '/'; } redirectUri += 'oauth3.html'; } params.redirect_uri = redirectUri; uri += '?' + core.querystringify(params); result = { url: uri , state: state , method: args.method , query: params }; return result; }; core.loginCode = function (directive, username, opts) { // // Example Resource Owner Password Request // (generally for 1st party and direct-partner mobile apps, and webapps) // // POST https://api.example.com/api/org.oauth3.provider/otp // { "request_otp": true, "client_id": "<>", "scope": "<>" // , "username": "<>" } // opts = opts || {}; var clientId = opts.appId || opts.clientId; var args = directive.otp; var params = { "username": username || opts.id || opts.username , "request_otp": true // opts.requestOtp || undefined //, "jwt": opts.jwt // TODO sign a proof }; var uri = args.url; var body; if (opts.clientUri) { params.client_uri = opts.clientUri; } if (opts.clientAgreeTos) { params.client_agree_tos = opts.clientAgreeTos; } if (clientId) { params.client_id = clientId; } if ('GET' === args.method.toUpperCase()) { uri += '?' + core.querystringify(params); } else { body = params; } return { url: uri , method: args.method , data: body }; }; core.resourceOwnerPassword = function (directive, username, passphrase, opts) { // // Example Resource Owner Password Request // (generally for 1st party and direct-partner mobile apps, and webapps) // // POST https://example.com/api/org.oauth3.provider/access_token // { "grant_type": "password", "client_id": "<>", "scope": "<>" // , "username": "<>", "password": "password" } // opts = opts || {}; var type = 'access_token'; var grantType = 'password'; var scope = opts.scope || directive.authn_scope; var clientId = opts.appId; var clientAgreeTos = opts.clientAgreeTos; var clientUri = opts.clientUri; var args = directive[type]; var params = { "grant_type": grantType , "username": username , "password": passphrase //, "totp": opts.totp }; var uri = args.url; var body; if (opts.totp) { params.totp = opts.totp; } if (clientId) { params.clientId = clientId; } if (clientUri) { params.clientUri = clientUri; params.clientAgreeTos = clientAgreeTos; if (!clientAgreeTos) { throw new Error('Developer Error: missing clientAgreeTos uri'); } } if (scope) { if (Array.isArray(scope)) { scope = scope.join(' '); } params.scope = scope; } if ('GET' === args.method.toUpperCase()) { uri += '?' + core.querystringify(params); } else { body = params; } return { url: uri , method: args.method , data: body }; }; exports.OAUTH3 = exports.OAUTH3 || { core: core }; exports.OAUTH3_CORE = core.OAUTH3_CORE = core; if ('undefined' !== typeof module) { module.exports = core; } }('undefined' !== typeof exports ? exports : window));