complete redirect flow
This commit is contained in:
		
							parent
							
								
									c2370d9b76
								
							
						
					
					
						commit
						bb6bcd826e
					
				| @ -7,11 +7,13 @@ | |||||||
|       clientUri: function (location) { |       clientUri: function (location) { | ||||||
|         return OAUTH3.utils.uri.normalize(location.host + location.pathname); |         return OAUTH3.utils.uri.normalize(location.host + location.pathname); | ||||||
|       } |       } | ||||||
|     , _formatError: function (providerUri, params) { |     , _error: { | ||||||
|         var err = new Error(params.error_description || params.error.message || "Unknown error with provider '" + providerUri + "'"); |         parse: function (providerUri, params) { | ||||||
|         err.uri = params.error_uri || params.error.uri; |           var err = new Error(params.error_description || params.error.message || "Unknown error with provider '" + providerUri + "'"); | ||||||
|         err.code = params.error.code || params.error; |           err.uri = params.error_uri || params.error.uri; | ||||||
|         return err; |           err.code = params.error.code || params.error; | ||||||
|  |           return err; | ||||||
|  |         } | ||||||
|       } |       } | ||||||
|     , atob: function (base64) { |     , atob: function (base64) { | ||||||
|         return (exports.atob || require('atob'))(base64); |         return (exports.atob || require('atob'))(base64); | ||||||
| @ -130,7 +132,7 @@ | |||||||
|         // 'abc.qrs.xyz'
 |         // 'abc.qrs.xyz'
 | ||||||
|         // [ 'abc', 'qrs', 'xyz' ]
 |         // [ 'abc', 'qrs', 'xyz' ]
 | ||||||
|         // [ {}, {}, 'foo' ]
 |         // [ {}, {}, 'foo' ]
 | ||||||
|         // { header: {}, payload: {}, signature: }
 |         // { header: {}, payload: {}, signature: '' }
 | ||||||
|         var parts = str.split(/\./g); |         var parts = str.split(/\./g); | ||||||
|         var jsons = parts.slice(0, 2).map(function (urlsafe64) { |         var jsons = parts.slice(0, 2).map(function (urlsafe64) { | ||||||
|           var atob = exports.atob || require('atob'); |           var atob = exports.atob || require('atob'); | ||||||
| @ -676,6 +678,8 @@ | |||||||
|           return OAUTH3.request({ |           return OAUTH3.request({ | ||||||
|             method: 'GET' |             method: 'GET' | ||||||
|           , url: OAUTH3.utils.url.normalize(providerUri) + '/.well-known/oauth3/directives.json' |           , url: OAUTH3.utils.url.normalize(providerUri) + '/.well-known/oauth3/directives.json' | ||||||
|  |           }).then(function (resp) { | ||||||
|  |             return resp.data; | ||||||
|           }); |           }); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| @ -913,6 +917,8 @@ | |||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   }; |   }; | ||||||
|  |   OAUTH3.utils._formatError = OAUTH3.utils._error.parse; | ||||||
|  | 
 | ||||||
|   if ('undefined' !== typeof Promise) { |   if ('undefined' !== typeof Promise) { | ||||||
|     OAUTH3.PromiseA = Promise; |     OAUTH3.PromiseA = Promise; | ||||||
|   } |   } | ||||||
|  | |||||||
							
								
								
									
										764
									
								
								oauth3.issuer.js
									
									
									
									
									
								
							
							
						
						
									
										764
									
								
								oauth3.issuer.js
									
									
									
									
									
								
							| @ -3,285 +3,549 @@ | |||||||
| 'use strict'; | 'use strict'; | ||||||
| 
 | 
 | ||||||
| OAUTH3.utils.query.parse = function (search) { | OAUTH3.utils.query.parse = function (search) { | ||||||
|     // parse a query or a hash
 |   // parse a query or a hash
 | ||||||
|     if (-1 !== ['#', '?'].indexOf(search[0])) { |   if (-1 !== ['#', '?'].indexOf(search[0])) { | ||||||
|       search = search.substring(1); |     search = search.substring(1); | ||||||
|  |   } | ||||||
|  |   // Solve for case of search within hash
 | ||||||
|  |   // example: #/authorization_dialog/?state=...&redirect_uri=...
 | ||||||
|  |   var queryIndex = search.indexOf('?'); | ||||||
|  |   if (-1 !== queryIndex) { | ||||||
|  |     search = search.substr(queryIndex + 1); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   var args = search.split('&'); | ||||||
|  |   var argsParsed = {}; | ||||||
|  |   var i, arg, kvp, key, value; | ||||||
|  | 
 | ||||||
|  |   for (i = 0; i < args.length; i += 1) { | ||||||
|  |     arg = args[i]; | ||||||
|  |     if (-1 === arg.indexOf('=')) { | ||||||
|  |       argsParsed[decodeURIComponent(arg).trim()] = true; | ||||||
|     } |     } | ||||||
|     // Solve for case of search within hash
 |     else { | ||||||
|     // example: #/authorization_dialog/?state=...&redirect_uri=...
 |       kvp = arg.split('='); | ||||||
|     var queryIndex = search.indexOf('?'); |       key = decodeURIComponent(kvp[0]).trim(); | ||||||
|     if (-1 !== queryIndex) { |       value = decodeURIComponent(kvp[1]).trim(); | ||||||
|       search = search.substr(queryIndex + 1); |       argsParsed[key] = value; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   return argsParsed; | ||||||
|  | }; | ||||||
|  | OAUTH3.utils.scope.parse = function (scope) { | ||||||
|  |   return (scope||'').split(/[, ]/g); | ||||||
|  | }; | ||||||
|  | OAUTH3.utils.url.parse = function (url) { | ||||||
|  |   // TODO browser
 | ||||||
|  |   // Node should replace this
 | ||||||
|  |   var parser = document.createElement('a'); | ||||||
|  |   parser.href = url; | ||||||
|  |   return parser; | ||||||
|  | }; | ||||||
|  | OAUTH3.utils.url._isRedirectHostSafe = function (referrerUrl, redirectUrl) { | ||||||
|  |   var src = OAUTH3.utils.url.parse(referrerUrl); | ||||||
|  |   var dst = OAUTH3.utils.url.parse(redirectUrl); | ||||||
|  | 
 | ||||||
|  |   // TODO how should we handle subdomains?
 | ||||||
|  |   // It should be safe for api.example.com to redirect to example.com
 | ||||||
|  |   // But it may not be safe for to example.com to redirect to aj.example.com
 | ||||||
|  |   // It is also probably not safe for sally.example.com to redirect to john.example.com
 | ||||||
|  |   // The client should have a list of allowed URLs to choose from and perhaps a wildcard will do
 | ||||||
|  |   //
 | ||||||
|  |   // api.example.com.evil.com SHOULD NOT match example.com
 | ||||||
|  |   return dst.hostname === src.hostname; | ||||||
|  | }; | ||||||
|  | OAUTH3.utils.url.checkRedirect = function (client, query) { | ||||||
|  |   console.warn("[security] URL path checking not yet implemented"); | ||||||
|  | 
 | ||||||
|  |   var clientUrl = OAUTH3.utils.url.normalize(client.url); | ||||||
|  |   var redirectUrl = OAUTH3.utils.url.normalize(query.redirect_uri); | ||||||
|  | 
 | ||||||
|  |   // General rule:
 | ||||||
|  |   // I can callback to a shorter domain (fewer subs) or a shorter path (on the same domain)
 | ||||||
|  |   // but not a longer (more subs) or different domain or a longer path (on the same domain)
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |   // We can callback to an explicitly listed domain (TODO and path)
 | ||||||
|  |   if (OAUTH3.utils.url._isRedirectHostSafe(clientUrl, redirectUrl)) { | ||||||
|  |     return true; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   return false; | ||||||
|  | }; | ||||||
|  | OAUTH3.utils.url.redirect = function (clientParams, grants, tokenOrError) { | ||||||
|  |   // TODO OAUTH3.redirect(clientParams, grants, tokenOrError)
 | ||||||
|  |   // TODO check redirect safeness right here with grants.client.urls
 | ||||||
|  |   // TODO check for '#' and '?'. If none, issue warning and use '?' (for backwards compat)
 | ||||||
|  | 
 | ||||||
|  |   var authz = { | ||||||
|  |     access_token: tokenOrError.access_token | ||||||
|  |   , token_type: tokenOrError.token_type         // 'Bearer'
 | ||||||
|  |   , refresh_token: tokenOrError.refresh_token | ||||||
|  |   , expires_in: tokenOrError.expires_in         // 1800 (but superceded by jwt.exp)
 | ||||||
|  |   , scope: tokenOrError.scope                   // superceded by jwt.scp
 | ||||||
|  | 
 | ||||||
|  |   , state: clientParams.state | ||||||
|  |   , debug: clientParams.debug | ||||||
|  |   }; | ||||||
|  |   if (tokenOrError.error) { | ||||||
|  |     authz.error = tokenOrError.error.code || tokenOrError.error; | ||||||
|  |     authz.error_description = tokenOrError.error.message || tokenOrError.error_description; | ||||||
|  |     authz.error_uri = tokenOrError.error.uri || tokenOrError.error_uri; | ||||||
|  |   } | ||||||
|  |   var redirect = clientParams.redirect_uri + '#' + window.OAUTH3.utils.query.stringify(authz); | ||||||
|  | 
 | ||||||
|  |   if (clientParams.debug) { | ||||||
|  |     console.info('final redirect_uri:', redirect); | ||||||
|  |     window.alert("You're in debug mode so we've taken a pause. Hit OK to continue"); | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   window.location = redirect; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | OAUTH3.urls.resourceOwnerPassword = function (directive, 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": "<<id>>", "scope": "<<scope>>"
 | ||||||
|  |   //    , "username": "<<username>>", "password": "password" }
 | ||||||
|  |   //
 | ||||||
|  |   opts = opts || {}; | ||||||
|  |   var type = 'access_token'; | ||||||
|  |   var grantType = 'password'; | ||||||
|  | 
 | ||||||
|  |   if (!opts.password) { | ||||||
|  |     if (opts.otp) { | ||||||
|  |       // for backwards compat
 | ||||||
|  |       opts.password = opts.otp; // 'otp:' + opts.otpUuid + ':' + opts.otp;
 | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   var scope = opts.scope || directive.authn_scope; | ||||||
|  |   var clientId = opts.appId || opts.clientId || opts.client_id; | ||||||
|  |   var clientAgreeTos = opts.clientAgreeTos || opts.client_agree_tos; | ||||||
|  |   var clientUri = opts.clientUri || opts.client_uri || opts.clientUrl || opts.client_url; | ||||||
|  |   var args = directive[type]; | ||||||
|  |   var otpCode = opts.otp || opts.otpCode || opts.otp_code || opts.otpToken || opts.otp_token || undefined; | ||||||
|  |   var params = { | ||||||
|  |     "grant_type": grantType | ||||||
|  |   , "username": opts.username | ||||||
|  |   , "password": opts.password || otpCode || undefined | ||||||
|  |   , "totp": opts.totp || opts.totpToken || opts.totp_token || undefined | ||||||
|  |   , "otp": otpCode | ||||||
|  |   , "password_type": otpCode && 'otp' | ||||||
|  |   , "otp_code": otpCode | ||||||
|  |   , "otp_uuid": opts.otpUuid || opts.otp_uuid || undefined | ||||||
|  |   , "user_agent": opts.userAgent || opts.useragent || opts.user_agent || undefined // AJ's Macbook
 | ||||||
|  |   , "jwk": (opts.rememberDevice || opts.remember_device) && opts.jwk || undefined | ||||||
|  |   //, "public_key": opts.rememberDevice && opts.publicKey || undefined
 | ||||||
|  |   //, "public_key_type":  opts.rememberDevice && opts.publicKeyType || undefined // RSA/ECDSA
 | ||||||
|  |   //, "jwt": opts.jwt // TODO sign a proof with a previously loaded public_key
 | ||||||
|  |   , debug: opts.debug || undefined | ||||||
|  |   }; | ||||||
|  |   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) { | ||||||
|  |     params.scope = OAUTH3.utils.scope.stringify(scope); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   if ('GET' === args.method.toUpperCase()) { | ||||||
|  |     uri += '?' + OAUTH3.utils.query.stringify(params); | ||||||
|  |   } else { | ||||||
|  |     body = params; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   return { | ||||||
|  |     url: uri | ||||||
|  |   , method: args.method | ||||||
|  |   , data: body | ||||||
|  |   }; | ||||||
|  | }; | ||||||
|  | OAUTH3.urls.grants = function (directive, opts) { | ||||||
|  |   // directive = { issuer, authorization_decision }
 | ||||||
|  |   // opts = { response_type, scopes{ granted, requested, pending, accepted } }
 | ||||||
|  | 
 | ||||||
|  |   if (!opts) { | ||||||
|  |     throw new Error("You must supply a directive and an options object."); | ||||||
|  |   } | ||||||
|  |   if (!opts.client_id) { | ||||||
|  |     throw new Error("You must supply options.client_id."); | ||||||
|  |   } | ||||||
|  |   if (!opts.session) { | ||||||
|  |     throw new Error("You must supply options.session."); | ||||||
|  |   } | ||||||
|  |   if (!opts.referrer) { | ||||||
|  |     console.warn("You should supply options.referrer"); | ||||||
|  |   } | ||||||
|  |   if (!opts.method) { | ||||||
|  |     console.warn("You must supply options.method as either 'GET', or 'POST'"); | ||||||
|  |   } | ||||||
|  |   if ('POST' === opts.method) { | ||||||
|  |     if ('string' !== typeof opts.scope) { | ||||||
|  |       console.warn("You should supply options.scope as a space-delimited string of scopes"); | ||||||
|  |     } | ||||||
|  |     if (-1 === ['token', 'code'].indexOf(opts.response_type)) { | ||||||
|  |       throw new Error("You must supply options.response_type as 'token' or 'code'"); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   var url = OAUTH3.utils.url.resolve(directive.issuer, directive.grants.url) | ||||||
|  |     .replace(/(:azp|:client_id)/g, OAUTH3.utils.uri.normalize(opts.client_id || opts.client_uri)) | ||||||
|  |     .replace(/(:sub|:account_id)/g, opts.session.token.sub) | ||||||
|  |     ; | ||||||
|  |   var data = { | ||||||
|  |     client_id: opts.client_id | ||||||
|  |   , client_uri: opts.client_uri | ||||||
|  |   , referrer: opts.referrer | ||||||
|  |   , response_type: opts.response_type | ||||||
|  |   , scope: opts.scope | ||||||
|  |   , tenant_id: opts.tenant_id | ||||||
|  |   }; | ||||||
|  |   var body; | ||||||
|  | 
 | ||||||
|  |   if ('GET' === opts.method) { | ||||||
|  |     url += '?' + OAUTH3.utils.query.stringify(data); | ||||||
|  |   } | ||||||
|  |   else { | ||||||
|  |     body = data; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   return { | ||||||
|  |     method: opts.method | ||||||
|  |   , url: url | ||||||
|  |   , data: body | ||||||
|  |   , session: opts.session | ||||||
|  |   }; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | OAUTH3.authn = {}; | ||||||
|  | 
 | ||||||
|  | OAUTH3.authz = {}; | ||||||
|  | OAUTH3.authz.loginMeta = function (directive, opts) { | ||||||
|  |   if (opts.mock) { | ||||||
|  |     if (opts.mockError) { | ||||||
|  |       return OAUTH3.PromiseA.resolve({data: {error: {message: "Yikes!", code: 'E'}}}); | ||||||
|  |     } | ||||||
|  |     return OAUTH3.PromiseA.resolve({data: {}}); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   return OAUTH3.request({ | ||||||
|  |     method: directive.credential_meta.method || 'GET' | ||||||
|  |     // TODO lint urls
 | ||||||
|  |   , url: OAUTH3.utils.url.resolve(directive.issuer, directive.credential_meta.url) | ||||||
|  |       .replace(':type', 'email') | ||||||
|  |       .replace(':id', opts.email) | ||||||
|  |   }); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | OAUTH3.authz.otp = function (directive, opts) { | ||||||
|  |   if (opts.mock) { | ||||||
|  |     if (opts.mockError) { | ||||||
|  |       return OAUTH3.PromiseA.resolve({data: {error: {message: "Yikes!", code: 'E'}}}); | ||||||
|  |     } | ||||||
|  |     return OAUTH3.PromiseA.resolve({data: {uuid: "uuidblah"}}); | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   return OAUTH3.request({ | ||||||
|  |     method: directive.credential_otp.url.method || 'POST' | ||||||
|  |   , url: OAUTH3.utils.url.resolve(directive.issuer, directive.credential_otp.url) | ||||||
|  |   , data: { | ||||||
|  |       // TODO replace with signed hosted file
 | ||||||
|  |       client_agree_tos: 'oauth3.org/tos/draft' | ||||||
|  |     , client_id: directive.issuer // In this case, the issuer is its own client
 | ||||||
|  |     , client_uri: directive.issuer | ||||||
|  |     , request_otp: true | ||||||
|  |     , username: opts.email | ||||||
|  |     } | ||||||
|  |   }); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | OAUTH3.authz.resourceOwnerPassword = function (directive, opts) { | ||||||
|  |   console.log('ginger bread man'); | ||||||
|  |   var providerUri = directive.issuer; | ||||||
|  | 
 | ||||||
|  |   //var scope = opts.scope;
 | ||||||
|  |   //var appId = opts.appId;
 | ||||||
|  |   return OAUTH3.discover(providerUri, opts).then(function (directive) { | ||||||
|  |     var prequest = OAUTH3.urls.resourceOwnerPassword(directive, opts); | ||||||
|  | 
 | ||||||
|  |     return OAUTH3.request(prequest).then(function (req) { | ||||||
|  |       var data = req.data; | ||||||
|  |       data.provider_uri = providerUri; | ||||||
|  |       if (data.error) { | ||||||
|  |         return oauth3.PromiseA.reject(OAUTH3.utils._error.parse(providerUri, data.error)); | ||||||
|  |       } | ||||||
|  |       return OAUTH3.hooks.refreshSession( | ||||||
|  |         opts.session || { provider_uri: providerUri, client_uri: opts.client_uri || opts.clientUri } | ||||||
|  |       , data | ||||||
|  |       ); | ||||||
|  |     }); | ||||||
|  |   }); | ||||||
|  | }; | ||||||
|  | OAUTH3.authz.scopes = function (providerUri, session, clientParams) { | ||||||
|  |   if (clientParams.mock) { | ||||||
|  |     return { | ||||||
|  |       pending: ['oauth3_authn']   // not yet accepted
 | ||||||
|  |     , granted: []                 // all granted, ever
 | ||||||
|  |     , requested: ['oauth3_authn'] // all requested, now
 | ||||||
|  |     , accepted: []                // granted (ever) and requested (now)
 | ||||||
|  |     }; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   // OAuth3.requests.grants(providerUri, {});         // return list of grants
 | ||||||
|  |   // OAuth3.checkGrants(providerUri, {});             //
 | ||||||
|  |   var clientUri = OAUTH3.utils.uri.normalize(clientParams.client_uri || OAUTH3._browser.window.document.referrer); | ||||||
|  |   var scope = clientParams.scope || ''; | ||||||
|  |   var clientObj = clientParams; | ||||||
|  | 
 | ||||||
|  |   if (!scope) { | ||||||
|  |     scope = 'oauth3_authn'; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   //$('.js-user-avatar').attr('src', userAvatar);
 | ||||||
|  | 
 | ||||||
|  |   /* | ||||||
|  |   console.log('grants options'); | ||||||
|  |   console.log(loc.hash); | ||||||
|  |   console.log(loc.search); | ||||||
|  |   console.log(clientObj); | ||||||
|  |   console.log(session.token); | ||||||
|  |   console.log(window.document.referrer); | ||||||
|  |   */ | ||||||
|  | 
 | ||||||
|  |   return OAUTH3.authz.grants(providerUri, { | ||||||
|  |     method: 'GET' | ||||||
|  |   , client_id: clientUri | ||||||
|  |   , client_uri: clientUri | ||||||
|  |   , session: session | ||||||
|  |   }).then(function (grantResults) { | ||||||
|  |     var grants; | ||||||
|  |     var grantedScopes; | ||||||
|  |     var grantedScopesMap; | ||||||
|  |     var pendingScopes; | ||||||
|  |     var acceptedScopes; | ||||||
|  |     var scopes = scope.split(/[+, ]/g); | ||||||
|  |     var callbackUrl; | ||||||
|  | 
 | ||||||
|  |     // it doesn't matter who the referrer is as long as the destination
 | ||||||
|  |     // is an authorized destination for the client in question
 | ||||||
|  |     // (though it may not hurt to pass the referrer's info on to the client)
 | ||||||
|  |     if (!OAUTH3.utils.url.checkRedirect(grantResults.client, clientObj)) { | ||||||
|  |       callbackUrl = 'https://oauth3.org/docs/errors#E_REDIRECT_ATTACK' | ||||||
|  |         + '?redirect_uri=' + clientObj.redirect_uri | ||||||
|  |         + '&allowed_urls=' + grantResults.client.url | ||||||
|  |         + '&client_id=' + clientUri | ||||||
|  |         + '&referrer_uri=' + OAUTH3.utils.uri.normalize(window.document.referrer) | ||||||
|  |         ; | ||||||
|  |       if (opts.debug) { | ||||||
|  |         console.log('grantResults Redirect Attack'); | ||||||
|  |         console.log(grantResults); | ||||||
|  |         console.log(clientObj); | ||||||
|  |         window.alert("DEBUG MODE checkRedirect error encountered. Check the console."); | ||||||
|  |       } | ||||||
|  |       location.href = callbackUrl; | ||||||
|  |       return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     var args = search.split('&'); |     if ('oauth3_authn' === scope) { | ||||||
|     var argsParsed = {}; |       // implicit ppid grant is automatic
 | ||||||
|     var i, arg, kvp, key, value; |       console.warn('[security] fix scope checking on backend so that we can do automatic grants'); | ||||||
|  |       // TODO check user preference if implicit ppid grant is allowed
 | ||||||
|  |       //return generateToken(session, clientObj);
 | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     for (i = 0; i < args.length; i += 1) { |     grants = (grantResults).grants.filter(function (grant) { | ||||||
|         arg = args[i]; |       if (clientUri === (grant.azp || grant.oauth_client_id || grant.oauthClientId)) { | ||||||
|         if (-1 === arg.indexOf('=')) { |         return true; | ||||||
|           argsParsed[decodeURIComponent(arg).trim()] = true; |       } | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     grantedScopesMap = {}; | ||||||
|  |     acceptedScopes = []; | ||||||
|  |     pendingScopes = scopes.filter(function (requestedScope) { | ||||||
|  |       return grants.every(function (grant) { | ||||||
|  |         if (!grant.scope) { | ||||||
|  |           grant.scope = 'oauth3_authn'; | ||||||
|  |         } | ||||||
|  |         var gscopes = grant.scope.split(/[+, ]/g); | ||||||
|  |         gscopes.forEach(function (s) { grantedScopesMap[s] = true; }); | ||||||
|  |         if (-1 !== gscopes.indexOf(requestedScope)) { | ||||||
|  |           // already accepted in the past
 | ||||||
|  |           acceptedScopes.push(requestedScope); | ||||||
|         } |         } | ||||||
|         else { |         else { | ||||||
|           kvp = arg.split('='); |           // true, is pending
 | ||||||
|           key = decodeURIComponent(kvp[0]).trim(); |           return true; | ||||||
|           value = decodeURIComponent(kvp[1]).trim(); |  | ||||||
|           argsParsed[key] = value; |  | ||||||
|         } |         } | ||||||
|     } |       }); | ||||||
|     return argsParsed; |     }); | ||||||
|   }; |     grantedScopes = Object.keys(grantedScopesMap); | ||||||
| 
 |  | ||||||
|   OAUTH3.urls.resourceOwnerPassword = function (directive, 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": "<<id>>", "scope": "<<scope>>"
 |  | ||||||
|     //    , "username": "<<username>>", "password": "password" }
 |  | ||||||
|     //
 |  | ||||||
|     opts = opts || {}; |  | ||||||
|     var type = 'access_token'; |  | ||||||
|     var grantType = 'password'; |  | ||||||
| 
 |  | ||||||
|     if (!opts.password) { |  | ||||||
|       if (opts.otp) { |  | ||||||
|         // for backwards compat
 |  | ||||||
|         opts.password = opts.otp; // 'otp:' + opts.otpUuid + ':' + opts.otp;
 |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     var scope = opts.scope || directive.authn_scope; |  | ||||||
|     var clientId = opts.appId || opts.clientId || opts.client_id; |  | ||||||
|     var clientAgreeTos = opts.clientAgreeTos || opts.client_agree_tos; |  | ||||||
|     var clientUri = opts.clientUri || opts.client_uri || opts.clientUrl || opts.client_url; |  | ||||||
|     var args = directive[type]; |  | ||||||
|     var otpCode = opts.otp || opts.otpCode || opts.otp_code || opts.otpToken || opts.otp_token || undefined; |  | ||||||
|     var params = { |  | ||||||
|       "grant_type": grantType |  | ||||||
|     , "username": opts.username |  | ||||||
|     , "password": opts.password || otpCode || undefined |  | ||||||
|     , "totp": opts.totp || opts.totpToken || opts.totp_token || undefined |  | ||||||
|     , "otp": otpCode |  | ||||||
|     , "password_type": otpCode && 'otp' |  | ||||||
|     , "otp_code": otpCode |  | ||||||
|     , "otp_uuid": opts.otpUuid || opts.otp_uuid || undefined |  | ||||||
|     , "user_agent": opts.userAgent || opts.useragent || opts.user_agent || undefined // AJ's Macbook
 |  | ||||||
|     , "jwk": (opts.rememberDevice || opts.remember_device) && opts.jwk || undefined |  | ||||||
|     //, "public_key": opts.rememberDevice && opts.publicKey || undefined
 |  | ||||||
|     //, "public_key_type":  opts.rememberDevice && opts.publicKeyType || undefined // RSA/ECDSA
 |  | ||||||
|     //, "jwt": opts.jwt // TODO sign a proof with a previously loaded public_key
 |  | ||||||
|     , debug: opts.debug || undefined |  | ||||||
|     }; |  | ||||||
|     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) { |  | ||||||
|       params.scope = core.stringifyscope(scope); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if ('GET' === args.method.toUpperCase()) { |  | ||||||
|       uri += '?' + core.querystringify(params); |  | ||||||
|     } else { |  | ||||||
|       body = params; |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     return { |     return { | ||||||
|       url: uri |       pending: pendingScopes    // not yet accepted
 | ||||||
|     , method: args.method |     , granted: grantedScopes    // all granted, ever
 | ||||||
|     , data: body |     , requested: scopes         // all requested, now
 | ||||||
|  |     , accepted: acceptedScopes  // granted (ever) and requested (now)
 | ||||||
|     }; |     }; | ||||||
|   }; |   }); | ||||||
|  | }; | ||||||
|  | OAUTH3.authz.grants = function (providerUri, opts) { | ||||||
|  |   return OAUTH3.discover(providerUri, { | ||||||
|  |     client_id: providerUri | ||||||
|  |   , debug: opts.debug | ||||||
|  |   }).then(function (directive) { | ||||||
|  |     console.log('providerUri', providerUri); | ||||||
|  |     console.log('directive', directive); | ||||||
| 
 | 
 | ||||||
|   OAUTH3.authz = {}; |     return OAUTH3.request(OAUTH3.urls.grants(directive, opts), opts).then(function (grantsResult) { | ||||||
|   OAUTH3.authz.loginMeta = function (directive, opts) { |       if ('POST' === opts.method) { | ||||||
|     if (opts.mock) { |         // TODO this is clientToken
 | ||||||
|       if (opts.mockError) { |         return grantsResult.originalData || grantsResult.data; | ||||||
|         return OAUTH3.PromiseA.resolve({data: {error: {message: "Yikes!", code: 'E'}}}); |  | ||||||
|       } |  | ||||||
|       return OAUTH3.PromiseA.resolve({data: {}}); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return OAUTH3.request({ |  | ||||||
|       method: directive.credential_meta.method || 'GET' |  | ||||||
|       // TODO lint urls
 |  | ||||||
|     , url: OAUTH3.utils.url.resolve(directive.issuer, directive.credential_meta.url) |  | ||||||
|         .replace(':type', 'email') |  | ||||||
|         .replace(':id', opts.email) |  | ||||||
|     }); |  | ||||||
|   }; |  | ||||||
| 
 |  | ||||||
|   OAUTH3.authz.otp = function (directive, opts) { |  | ||||||
|     if (opts.mock) { |  | ||||||
|       if (opts.mockError) { |  | ||||||
|         return OAUTH3.PromiseA.resolve({data: {error: {message: "Yikes!", code: 'E'}}}); |  | ||||||
|       } |  | ||||||
|       return OAUTH3.PromiseA.resolve({data: {uuid: "uuidblah"}}); |  | ||||||
|     } |  | ||||||
|      |  | ||||||
|     return OAUTH3.request({ |  | ||||||
|       method: directive.credential_otp.url.method || 'POST' |  | ||||||
|     , url: OAUTH3.utils.url.resolve(directive.issuer, directive.credential_otp.url) |  | ||||||
|     , data: { |  | ||||||
|         // TODO replace with signed hosted file
 |  | ||||||
|         client_agree_tos: 'oauth3.org/tos/draft' |  | ||||||
|       , client_id: directive.issuer // In this case, the issuer is its own client
 |  | ||||||
|       , client_uri: directive.issuer |  | ||||||
|       , request_otp: true |  | ||||||
|       , username: opts.email |  | ||||||
|       } |  | ||||||
|     }); |  | ||||||
|   }; |  | ||||||
| 
 |  | ||||||
|   OAUTH3.authz.resourceOwnerPassword = function (directive, opts) { |  | ||||||
|     var providerUri = directive.issuer; |  | ||||||
|     if (opts.mock) { |  | ||||||
|       if (opts.mockError) { |  | ||||||
|         return OAUTH3.PromiseA.resolve({data: {error_description: "fake error", error: "errorcode", error_uri: "https://blah"}}); |  | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|       //core.jwt.encode({header: {alg: 'none'}, payload: {exp: Date.now() / 1000 + 900, sub: 'fakeUserId'}, signature: "fakeSig" })
 |       var grants = grantsResult.originalData || grantsResult.data; | ||||||
|  |       // TODO
 | ||||||
|  |       if (grants.error) { | ||||||
|  |         return oauth3.PromiseA.reject(oauth3.utils._formatError(grants.error)); | ||||||
|  |       } | ||||||
| 
 | 
 | ||||||
|       return OAUTH3.PromiseA.resolve(OAUTH3.hooks.session.refresh( |       console.warn('requests.grants', grants); | ||||||
|         opts.session || { provider_uri: providerUri, client_uri: opts.client_uri || opts.clientUri } |  | ||||||
| 
 | 
 | ||||||
|       , { access_token: "eyJhbGciOiJub25lIn0.eyJleHAiOjE0ODc2MTQyMzUuNzg3LCJzdWIiOiJmYWtlVXNlcklkIn0.fakeSig" |       oauth3.hooks.setGrants(opts.client_id + '-client', grants.client); | ||||||
|         , refresh_token: "eyJhbGciOiJub25lIn0.eyJleHAiOjE0ODc2MTQyMzUuNzg3LCJzdWIiOiJmYWtlVXNlcklkIn0.fakeSig" |       grants.grants.forEach(function (grant) { | ||||||
|         , expires_in: "900" |         var clientId = grant.client_id || grant.oauth_client_id || grant.oauthClientId; | ||||||
|         } |         // TODO should save as an array
 | ||||||
|       )); |         oauth3.hooks.setGrants(clientId, [ grant ]); | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     //var scope = opts.scope;
 |  | ||||||
|     //var appId = opts.appId;
 |  | ||||||
|     return oauth3.discover(providerUri, opts).then(function (directive) { |  | ||||||
|       var prequest = core.urls.resourceOwnerPassword(directive, opts); |  | ||||||
| 
 |  | ||||||
|       return oauth3.request(prequest).then(function (req) { |  | ||||||
|         var data = (req.originalData || req.data); |  | ||||||
|         data.provider_uri = providerUri; |  | ||||||
|         if (data.error) { |  | ||||||
|           return oauth3.PromiseA.reject(oauth3.core.formatError(providerUri, data.error)); |  | ||||||
|         } |  | ||||||
|         return oauth3.hooks.refreshSession( |  | ||||||
|           opts.session || { provider_uri: providerUri, client_uri: opts.client_uri || opts.clientUri } |  | ||||||
|         , data |  | ||||||
|         ); |  | ||||||
|       }); |       }); | ||||||
|  | 
 | ||||||
|  |       return { | ||||||
|  |         client: oauth3.hooks.getGrants(opts.client_id + '-client') | ||||||
|  |       , grants: oauth3.hooks.getGrants(opts.client_id) || [] | ||||||
|  |       }; | ||||||
|     }); |     }); | ||||||
|   }; |   }); | ||||||
|  | }; | ||||||
|  | OAUTH3.authz.redirectWithToken = function (providerUri, session, clientParams, scopes) { | ||||||
|  |   console.info('redirectWithToken scopes'); | ||||||
|  |   console.log(scopes); | ||||||
| 
 | 
 | ||||||
|   OAUTH3.authz.redirectWithToken = function (providerUri, session, clientParams, scopes) { |   scopes.new = scopes.new || []; | ||||||
|     console.info('redirectWithToken scopes'); |  | ||||||
|     console.log(scopes); |  | ||||||
| 
 | 
 | ||||||
|     scopes.new = scopes.new || []; |   if ('token' === clientParams.response_type) { | ||||||
| 
 |     // get token and redirect client-side
 | ||||||
|     if ('token' === clientParams.response_type) { |     return OAUTH3.authz.grants(providerUri, { | ||||||
|       // get token and redirect client-side
 |  | ||||||
|       return OAUTH3.requests.grants(providerUri, { |  | ||||||
|         method: 'POST' |  | ||||||
|       , client_id: clientParams.client_uri |  | ||||||
|       , client_uri: clientParams.client_uri |  | ||||||
|       , scope: scopes.granted.concat(scopes.new).join(',') |  | ||||||
|       , response_type: clientParams.response_type |  | ||||||
|       , referrer: clientParams.referrer |  | ||||||
|       , session: session |  | ||||||
|       , debug: clientParams.debug |  | ||||||
|       }).then(function (results) { |  | ||||||
|         console.info('generate token results'); |  | ||||||
|         console.info(results); |  | ||||||
| 
 |  | ||||||
|         OAUTH3.redirect(clientParams, scopes, results); |  | ||||||
|       }); |  | ||||||
|     } |  | ||||||
|     else if ('code' === clientParams.response_type) { |  | ||||||
|       // get token and redirect server-side
 |  | ||||||
|       // (requires insecure form post as per spec)
 |  | ||||||
|       //OAUTH3.requests.authorizationDecision();
 |  | ||||||
|       window.alert("Authorization Code Redirect NOT IMPLEMENTED"); |  | ||||||
|       throw new Error("Authorization Code Redirect NOT IMPLEMENTED"); |  | ||||||
|     } |  | ||||||
|   }; |  | ||||||
|   OAUTH3.requests = {}; |  | ||||||
|   OAUTH3.requests.accounts = {}; |  | ||||||
|   OAUTH3.requests.accounts.update = function (directive, session, opts) { |  | ||||||
|     var dir = directive.update_account || { |  | ||||||
|       method: 'POST' |       method: 'POST' | ||||||
|     , url: 'https://' + directive.provider_url + '/api/org.oauth3.provider/accounts/:accountId' |     , client_id: clientParams.client_uri | ||||||
|     , bearer: 'Bearer' |     , client_uri: clientParams.client_uri | ||||||
|     }; |     , scope: scopes.granted.concat(scopes.new).join(',') | ||||||
|     var url = dir.url |     , response_type: clientParams.response_type | ||||||
|       .replace(/:accountId/, opts.accountId) |     , referrer: clientParams.referrer | ||||||
|     ; |     , session: session | ||||||
|  |     , debug: clientParams.debug | ||||||
|  |     }).then(function (results) { | ||||||
|  |       console.info('generate token results'); | ||||||
|  |       console.info(results); | ||||||
| 
 | 
 | ||||||
|     return OAUTH3.request({ |       OAUTH3.utils.url.redirect(clientParams, scopes, results); | ||||||
|       method: dir.method || 'POST' |  | ||||||
|     , url: url |  | ||||||
|     , headers: { |  | ||||||
|         'Authorization': (dir.bearer || 'Bearer') + ' ' + session.accessToken |  | ||||||
|       } |  | ||||||
|     , json: { |  | ||||||
|         name: opts.name |  | ||||||
|       , comment: opts.comment |  | ||||||
|       , displayName: opts.displayName |  | ||||||
|       , priority: opts.priority |  | ||||||
|       } |  | ||||||
|     }); |     }); | ||||||
|  |   } | ||||||
|  |   else if ('code' === clientParams.response_type) { | ||||||
|  |     // get token and redirect server-side
 | ||||||
|  |     // (requires insecure form post as per spec)
 | ||||||
|  |     //OAUTH3.requests.authorizationDecision();
 | ||||||
|  |     window.alert("Authorization Code Redirect NOT IMPLEMENTED"); | ||||||
|  |     throw new Error("Authorization Code Redirect NOT IMPLEMENTED"); | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  | OAUTH3.requests = {}; | ||||||
|  | OAUTH3.requests.accounts = {}; | ||||||
|  | OAUTH3.requests.accounts.update = function (directive, session, opts) { | ||||||
|  |   var dir = directive.update_account || { | ||||||
|  |     method: 'POST' | ||||||
|  |   , url: 'https://' + directive.provider_url + '/api/org.oauth3.provider/accounts/:accountId' | ||||||
|  |   , bearer: 'Bearer' | ||||||
|   }; |   }; | ||||||
|   OAUTH3.requests.accounts.create = function (directive, session, account) { |   var url = dir.url | ||||||
|     var dir = directive.create_account || { |     .replace(/:accountId/, opts.accountId) | ||||||
|       method: 'POST' |   ; | ||||||
|     , url: 'https://' + directive.issuer + '/api/org.oauth3.provider/accounts' | 
 | ||||||
|     , bearer: 'Bearer' |   return OAUTH3.request({ | ||||||
|     }; |     method: dir.method || 'POST' | ||||||
|     var data = { |   , url: url | ||||||
|       // TODO fix the server to just use one scheme
 |   , headers: { | ||||||
|       // account = { nick, self: { comment, username } }
 |       'Authorization': (dir.bearer || 'Bearer') + ' ' + session.accessToken | ||||||
|       // account = { name, comment, display_name, priority }
 |     } | ||||||
|       account: { |   , json: { | ||||||
|  |       name: opts.name | ||||||
|  |     , comment: opts.comment | ||||||
|  |     , displayName: opts.displayName | ||||||
|  |     , priority: opts.priority | ||||||
|  |     } | ||||||
|  |   }); | ||||||
|  | }; | ||||||
|  | OAUTH3.requests.accounts.create = function (directive, session, account) { | ||||||
|  |   var dir = directive.create_account || { | ||||||
|  |     method: 'POST' | ||||||
|  |   , url: 'https://' + directive.issuer + '/api/org.oauth3.provider/accounts' | ||||||
|  |   , bearer: 'Bearer' | ||||||
|  |   }; | ||||||
|  |   var data = { | ||||||
|  |     // TODO fix the server to just use one scheme
 | ||||||
|  |     // account = { nick, self: { comment, username } }
 | ||||||
|  |     // account = { name, comment, display_name, priority }
 | ||||||
|  |     account: { | ||||||
|  |       nick: account.display_name | ||||||
|  |     , name: account.name | ||||||
|  |     , comment: account.comment | ||||||
|  |     , display_name: account.display_name | ||||||
|  |     , priority: account.priority | ||||||
|  |     , self: { | ||||||
|         nick: account.display_name |         nick: account.display_name | ||||||
|       , name: account.name |       , name: account.name | ||||||
|       , comment: account.comment |       , comment: account.comment | ||||||
|       , display_name: account.display_name |       , display_name: account.display_name | ||||||
|       , priority: account.priority |       , priority: account.priority | ||||||
|       , self: { |  | ||||||
|           nick: account.display_name |  | ||||||
|         , name: account.name |  | ||||||
|         , comment: account.comment |  | ||||||
|         , display_name: account.display_name |  | ||||||
|         , priority: account.priority |  | ||||||
|         } |  | ||||||
|       } |       } | ||||||
|     , logins: [ |     } | ||||||
|         { |   , logins: [ | ||||||
|           token: session.access_token |       { | ||||||
|         } |         token: session.access_token | ||||||
|       ] |       } | ||||||
|     }; |     ] | ||||||
| 
 |  | ||||||
|     return OAUTH3.request({ |  | ||||||
|       method: dir.method || 'POST' |  | ||||||
|     , url: dir.url |  | ||||||
|     , session: session |  | ||||||
|     , data: data |  | ||||||
|     }); |  | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|  |   return OAUTH3.request({ | ||||||
|  |     method: dir.method || 'POST' | ||||||
|  |   , url: dir.url | ||||||
|  |   , session: session | ||||||
|  |   , data: data | ||||||
|  |   }); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | OAUTH3._browser.isIframe = function isIframe () { | ||||||
|  |   try { | ||||||
|  |     return window.self !== window.top; | ||||||
|  |   } catch (e) { | ||||||
|  |     return true; | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| }('undefined' !== typeof exports ? exports : window)); | }('undefined' !== typeof exports ? exports : window)); | ||||||
							
								
								
									
										81
									
								
								oauth3.issuer.mock.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								oauth3.issuer.mock.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,81 @@ | |||||||
|  | /* global Promise */ | ||||||
|  | ;(function (exports) { | ||||||
|  | 'use strict'; | ||||||
|  | 
 | ||||||
|  |   OAUTH3.utils._base64ToUrlSafeBase64 = function (b64) { | ||||||
|  |     // Base64 to URL-safe Base64
 | ||||||
|  |     b64 = b64.replace(/\+/g, '-').replace(/\//g, '_'); | ||||||
|  |     b64 = b64.replace(/=+/g, ''); | ||||||
|  |     return b64; | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   OAUTH3.jwt.encode = function (parts) { | ||||||
|  |     parts.header = parts.header || { alg: 'none', typ: 'jwt' }; | ||||||
|  |     parts.signature = parts.signature || ''; | ||||||
|  | 
 | ||||||
|  |     var btoa = exports.btoa || require('btoa'); | ||||||
|  |     var result = [ | ||||||
|  |       OAUTH3.utils._base64ToUrlSafeBase64(btoa(JSON.stringify(parts.header, null))) | ||||||
|  |     , OAUTH3.utils._base64ToUrlSafeBase64(btoa(JSON.stringify(parts.payload, null))) | ||||||
|  |     , parts.signature // should already be url-safe base64
 | ||||||
|  |     ].join('.'); | ||||||
|  | 
 | ||||||
|  |     return result; | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   OAUTH3.authn.resourceOwnerPassword = OAUTH3.authz.resourceOwnerPassword = function (directive, opts) { | ||||||
|  |     var providerUri = directive.issuer; | ||||||
|  | 
 | ||||||
|  |     if (opts.mockError) { | ||||||
|  |       return OAUTH3.PromiseA.resolve({data: {error_description: "fake error", error: "errorcode", error_uri: "https://blah"}}); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return OAUTH3._mockToken(providerUri, opts); | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   OAUTH3.authz.grants = function (providerUri, opts) { | ||||||
|  |     if ('POST' === opts.method) { | ||||||
|  |       return OAUTH3._mockToken(providerUri, opts); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return OAUTH3.discover(providerUri, { | ||||||
|  |       client_id: providerUri | ||||||
|  |     , debug: opts.debug | ||||||
|  |     }).then(function (directive) { | ||||||
|  |       return { | ||||||
|  |         client: { | ||||||
|  |           name: "foo" | ||||||
|  |         , client_id: "localhost.foo.daplie.me:8443" | ||||||
|  |         , url: "https://localhost.foo.daplie.me:8443" | ||||||
|  |         } | ||||||
|  |       , grants: [] | ||||||
|  |       }; | ||||||
|  |     }); | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   OAUTH3._refreshToken = function (providerUri, opts) { | ||||||
|  |     return OAUTH3._mockToken(providerUri, opts); | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   OAUTH3._mockToken = function (providerUri, opts) { | ||||||
|  |     var accessToken = OAUTH3.jwt.encode({ | ||||||
|  |       header: { alg: 'none' } | ||||||
|  |     , payload: { exp: Math.round(Date.now() / 1000) + 900, sub: 'fakeUserId', scp: opts.scope } | ||||||
|  |     , signature: "fakeSig" | ||||||
|  |     }); | ||||||
|  |    | ||||||
|  |     return OAUTH3.hooks.session.refresh( | ||||||
|  |       opts.session || { | ||||||
|  |         provider_uri: providerUri | ||||||
|  |       , client_id: opts.client_id | ||||||
|  |       , client_uri: opts.client_uri || opts.clientUri | ||||||
|  |       } | ||||||
|  |     , { access_token: accessToken | ||||||
|  |       , refresh_token: accessToken | ||||||
|  |       , expires_in: "900" | ||||||
|  |       , scope: opts.scope | ||||||
|  |       } | ||||||
|  |     ); | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  | }('undefined' !== typeof exports ? exports : window)); | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user