@okta/okta-auth-js
Advanced tools
Comparing version 1.4.0 to 1.5.0
@@ -65,13 +65,13 @@ /*! | ||
sdk.session = { | ||
close: util.bind(session.closeSession, sdk, sdk), | ||
exists: util.bind(session.sessionExists, sdk, sdk), | ||
get: util.bind(session.getSession, sdk, sdk), | ||
refresh: util.bind(session.refreshSession, sdk, sdk), | ||
setCookieAndRedirect: util.bind(session.setCookieAndRedirect, sdk, sdk) | ||
close: util.bind(session.closeSession, null, sdk), | ||
exists: util.bind(session.sessionExists, null, sdk), | ||
get: util.bind(session.getSession, null, sdk), | ||
refresh: util.bind(session.refreshSession, null, sdk), | ||
setCookieAndRedirect: util.bind(session.setCookieAndRedirect, null, sdk) | ||
}; | ||
sdk.tx = { | ||
status: util.bind(tx.transactionStatus, sdk, sdk), | ||
resume: util.bind(tx.resumeTransaction, sdk, sdk), | ||
exists: util.bind(tx.transactionExists, sdk, sdk) | ||
status: util.bind(tx.transactionStatus, null, sdk), | ||
resume: util.bind(tx.resumeTransaction, null, sdk), | ||
exists: util.bind(tx.transactionExists, null, sdk) | ||
}; | ||
@@ -85,6 +85,8 @@ | ||
sdk.idToken = { | ||
authorize: util.bind(token.getToken, sdk, sdk), // deprecated for sessionToken and idp flows | ||
verify: util.bind(token.verifyIdToken, sdk, sdk), | ||
refresh: util.bind(token.refreshIdToken, sdk, sdk), | ||
decode: util.bind(token.decodeToken, sdk) // deprecated | ||
authorize: util.deprecateWrap('Use token.getWithoutPrompt, token.getWithPopup, or token.getWithRedirect ' + | ||
'instead of idToken.authorize.', util.bind(token.getToken, null, sdk)), | ||
verify: util.bind(token.verifyIdToken, null, sdk), | ||
refresh: util.deprecateWrap('Use token.refresh instead of idToken.refresh', | ||
util.bind(token.refreshIdToken, null, sdk)), | ||
decode: util.deprecateWrap('Use token.decode instead of idToken.decode', token.decodeToken) | ||
}; | ||
@@ -98,7 +100,9 @@ | ||
sdk.token = { | ||
getWithoutPrompt: util.bind(token.getWithoutPrompt, sdk, sdk), | ||
getWithPopup: util.bind(token.getWithPopup, sdk, sdk), | ||
getWithRedirect: util.bind(token.getWithRedirect, sdk, sdk), | ||
parseFromUrl: util.bind(token.parseFromUrl, sdk, sdk), | ||
decode: util.bind(token.decodeToken, sdk) | ||
getWithoutPrompt: util.bind(token.getWithoutPrompt, null, sdk), | ||
getWithPopup: util.bind(token.getWithPopup, null, sdk), | ||
getWithRedirect: util.bind(token.getWithRedirect, null, sdk), | ||
parseFromUrl: util.bind(token.parseFromUrl, null, sdk), | ||
decode: token.decodeToken, | ||
refresh: util.bind(token.refreshToken, null, sdk), | ||
getUserInfo: util.bind(token.getUserInfo, null, sdk) | ||
}; | ||
@@ -105,0 +109,0 @@ |
@@ -5,6 +5,5 @@ module.exports = { | ||
"DEFAULT_MAX_CLOCK_SKEW": 300, | ||
"FRAME_ID": "okta-oauth-helper-frame", | ||
"REDIRECT_OAUTH_PARAMS_COOKIE_NAME": "okta-oauth-redirect-params", | ||
"TOKEN_STORAGE_NAME": "okta-token-storage", | ||
"SDK_VERSION": "1.4.0" | ||
"SDK_VERSION": "1.5.0" | ||
}; |
@@ -8,3 +8,10 @@ /* eslint-disable complexity */ | ||
function httpRequest(sdk, url, method, args, dontSaveResponse) { | ||
function httpRequest(sdk, options) { | ||
options = options || {}; | ||
var url = options.url, | ||
method = options.method, | ||
args = options.args, | ||
dontSaveResponse = options.dontSaveResponse, | ||
accessToken = options.accessToken; | ||
var headers = { | ||
@@ -17,3 +24,7 @@ 'Accept': 'application/json', | ||
var options = { | ||
if (accessToken && util.isString(accessToken)) { | ||
headers['Authorization'] = 'Bearer ' + accessToken; | ||
} | ||
var ajaxOptions = { | ||
headers: headers, | ||
@@ -24,3 +35,3 @@ data: args || undefined | ||
var err, res; | ||
return new Q(sdk.options.ajaxRequest(method, url, options)) | ||
return new Q(sdk.options.ajaxRequest(method, url, ajaxOptions)) | ||
.then(function(resp) { | ||
@@ -76,3 +87,7 @@ res = resp.responseText; | ||
url = util.isAbsoluteUrl(url) ? url : sdk.options.url + url; | ||
return httpRequest(sdk, url, 'GET', undefined, !saveResponse); | ||
return httpRequest(sdk, { | ||
url: url, | ||
method: 'GET', | ||
dontSaveResponse: !saveResponse | ||
}); | ||
} | ||
@@ -82,3 +97,8 @@ | ||
url = util.isAbsoluteUrl(url) ? url : sdk.options.url + url; | ||
return httpRequest(sdk, url, 'POST', args, dontSaveResponse); | ||
return httpRequest(sdk, { | ||
url: url, | ||
method: 'POST', | ||
args: args, | ||
dontSaveResponse: dontSaveResponse | ||
}); | ||
} | ||
@@ -85,0 +105,0 @@ |
@@ -39,3 +39,7 @@ var util = require('./util'); | ||
function closeSession(sdk) { | ||
return http.httpRequest(sdk, sdk.options.url + '/api/v1/sessions/me', 'DELETE', undefined, true); | ||
return http.httpRequest(sdk, { | ||
url: sdk.options.url + '/api/v1/sessions/me', | ||
method: 'DELETE', | ||
dontSaveResponse: true | ||
}); | ||
} | ||
@@ -42,0 +46,0 @@ |
154
lib/token.js
@@ -111,3 +111,3 @@ /* eslint-disable complexity, max-statements */ | ||
} | ||
var jwt = sdk.idToken.decode(idToken); | ||
var jwt = sdk.token.decode(idToken); | ||
@@ -131,21 +131,11 @@ if (isExpired(jwt.payload.exp)) { | ||
function refreshIdToken(sdk, opts) { | ||
opts = opts || {}; | ||
opts.display = null; | ||
opts.prompt = 'none'; | ||
return getToken(sdk, opts); | ||
function refreshIdToken(sdk, options) { | ||
options = options || {}; | ||
options.display = null; | ||
options.prompt = 'none'; | ||
return getToken(sdk, options); | ||
} | ||
function loadFrame(src, iframeId) { | ||
if (typeof iframeId === 'undefined') { | ||
return; | ||
} | ||
var iframe = document.getElementById(iframeId); | ||
if (iframe) { | ||
return iframe; | ||
} | ||
iframe = document.createElement('iframe'); | ||
iframe.setAttribute('id', iframeId); | ||
function loadFrame(src) { | ||
var iframe = document.createElement('iframe'); | ||
iframe.style.display = 'none'; | ||
@@ -180,7 +170,9 @@ iframe.src = src; | ||
function addPostMessageListener(sdk, timeout) { | ||
function addPostMessageListener(sdk, timeout, state) { | ||
var deferred = Q.defer(); | ||
function responseHandler(e) { | ||
if (!e.data || e.origin !== sdk.options.url) { | ||
if (!e.data || | ||
e.origin !== sdk.options.url || | ||
(e.data && util.isString(state) && e.data.state !== state)) { | ||
return; | ||
@@ -219,3 +211,3 @@ } | ||
// id_token should remain base64url encoded | ||
if (key === 'id_token' || key === 'access_token') { | ||
if (key === 'id_token' || key === 'access_token' || key === 'code') { | ||
obj[key] = value; | ||
@@ -272,3 +264,3 @@ } else { | ||
if (res['id_token']) { | ||
var jwt = sdk.idToken.decode(res['id_token']); | ||
var jwt = sdk.token.decode(res['id_token']); | ||
if (jwt.payload.nonce !== oauthParams.nonce) { | ||
@@ -310,2 +302,14 @@ throw new AuthSdkError('OAuth flow response nonce doesn\'t match request nonce'); | ||
if (res['code']) { | ||
var authorizationCode = { | ||
authorizationCode: res['code'] | ||
}; | ||
if (Array.isArray(tokenTypes)) { | ||
tokenDict['code'] = authorizationCode; | ||
} else { | ||
return authorizationCode; | ||
} | ||
} | ||
if (!tokenDict['token'] && !tokenDict['id_token']) { | ||
@@ -399,3 +403,3 @@ throw new AuthSdkError('Unable to parse OAuth flow response'); | ||
* | ||
* 1) Exchange a sessionToken for an idToken | ||
* 1) Exchange a sessionToken for a token | ||
* | ||
@@ -415,3 +419,3 @@ * Required: | ||
* | ||
* 2) Get an idToken from an idp | ||
* 2) Get a token from an idp | ||
* | ||
@@ -447,10 +451,5 @@ * Required: | ||
function getToken(sdk, oauthOptions, options) { | ||
if (!oauthOptions) { | ||
oauthOptions = {}; | ||
} | ||
oauthOptions = oauthOptions || {}; | ||
options = options || {}; | ||
if (!options) { | ||
options = {}; | ||
} | ||
// Default OAuth query params | ||
@@ -477,3 +476,8 @@ var oauthParams = getDefaultOAuthParams(sdk, oauthOptions); | ||
// Use the query params to build the authorize url | ||
var requestUrl = buildAuthorizeUrl(sdk, oauthParams); | ||
var requestUrl; | ||
try { | ||
requestUrl = buildAuthorizeUrl(sdk, oauthParams); | ||
} catch (e) { | ||
return Q.reject(e); | ||
} | ||
@@ -498,4 +502,4 @@ // Determine the flow type | ||
case 'IFRAME': | ||
var iframePromise = addPostMessageListener(sdk, options.timeout); | ||
var iframeEl = loadFrame(requestUrl, config.FRAME_ID); | ||
var iframePromise = addPostMessageListener(sdk, options.timeout, oauthParams.state); | ||
var iframeEl = loadFrame(requestUrl); | ||
return iframePromise | ||
@@ -520,3 +524,3 @@ .then(function(res) { | ||
} | ||
popupPromise = addPostMessageListener(sdk, options.timeout); | ||
popupPromise = addPostMessageListener(sdk, options.timeout, oauthParams.state); | ||
} | ||
@@ -598,5 +602,20 @@ | ||
var oauthParams = getDefaultOAuthParams(sdk, oauthOptions); | ||
util.extend(oauthParams, { | ||
responseMode: 'fragment' | ||
}); | ||
// If the user didn't specify a responseMode | ||
if (!oauthOptions.responseMode) { | ||
// And it's only an auth code request (responseType could be an array) | ||
var respType = oauthParams.responseType; | ||
if (respType.indexOf('code') !== -1 && | ||
(util.isString(respType) || (Array.isArray(respType) && respType.length === 1))) { | ||
// Default the responseMode to query | ||
util.extend(oauthParams, { | ||
responseMode: 'query' | ||
}); | ||
// Otherwise, default to fragment | ||
} else { | ||
util.extend(oauthParams, { | ||
responseMode: 'fragment' | ||
}); | ||
} | ||
} | ||
var requestUrl = buildAuthorizeUrl(sdk, oauthParams); | ||
@@ -615,2 +634,29 @@ | ||
function isToken(obj) { | ||
if (obj && | ||
(obj.accessToken || obj.idToken) && | ||
Array.isArray(obj.scopes)) { | ||
return true; | ||
} | ||
return false; | ||
} | ||
function refreshToken(sdk, token) { | ||
if (!isToken(token)) { | ||
return Q.reject(new AuthSdkError('Refresh must be passed a token with ' + | ||
'an array of scopes and an accessToken or idToken')); | ||
} | ||
var responseType; | ||
if (token.accessToken) { | ||
responseType = 'token'; | ||
} else { | ||
responseType = 'id_token'; | ||
} | ||
return sdk.token.getWithoutPrompt({ | ||
responseType: responseType, | ||
scopes: token.scopes | ||
}); | ||
} | ||
function parseFromUrl(sdk, url) { | ||
@@ -640,2 +686,30 @@ var hash = sdk.token.parseFromUrl._getLocationHash(); | ||
function getUserInfo(sdk, accessTokenObject) { | ||
if (!accessTokenObject || | ||
(!isToken(accessTokenObject) && !accessTokenObject.accessToken)) { | ||
return Q.reject(new AuthSdkError('getUserInfo requires an access token object')); | ||
} | ||
return http.httpRequest(sdk, { | ||
url: sdk.options.url + '/oauth2/v1/userinfo', | ||
method: 'GET', | ||
dontSaveResponse: true, | ||
accessToken: accessTokenObject.accessToken | ||
}) | ||
.fail(function(err) { | ||
if (err.xhr && (err.xhr.status === 401 || err.xhr.status === 403)) { | ||
var authenticateHeader = err.xhr.getResponseHeader('WWW-Authenticate'); | ||
if (authenticateHeader) { | ||
var errorMatches = authenticateHeader.match(/error="(.*?)"/) || []; | ||
var errorDescriptionMatches = authenticateHeader.match(/error_description="(.*?)"/) || []; | ||
var error = errorMatches[1]; | ||
var errorDescription = errorDescriptionMatches[1]; | ||
if (error && errorDescription) { | ||
err = new OAuthError(error, errorDescription); | ||
} | ||
} | ||
} | ||
throw err; | ||
}); | ||
} | ||
module.exports = { | ||
@@ -649,3 +723,5 @@ getToken: getToken, | ||
decodeToken: decodeToken, | ||
verifyIdToken: verifyIdToken | ||
verifyIdToken: verifyIdToken, | ||
refreshToken: refreshToken, | ||
getUserInfo: getUserInfo | ||
}; |
@@ -46,3 +46,3 @@ var util = require('./util'); | ||
return refresh(sdk, tokenMgmtRef, storage, key); | ||
} else if (token.expiresAt * 1000 < Date.now()) { | ||
} else if (token.expiresAt * 1000 <= Date.now()) { | ||
remove(tokenMgmtRef, storage, key); | ||
@@ -117,51 +117,18 @@ emitExpired(tokenMgmtRef, key, token); | ||
var responseType; | ||
if (token.accessToken) { | ||
responseType = 'token'; | ||
} else { | ||
responseType = 'id_token'; | ||
} | ||
// Remove existing autoRefresh timeout for this key | ||
clearRefreshTimeout(tokenMgmtRef, key); | ||
// We have to chain refreshes sequentially, because | ||
// we can't currently distinguish between multiple | ||
// iframes in our postMessage listeners | ||
var refreshDeferred = Q.defer(); | ||
function tokenRefreshWithoutPrompt() { | ||
return sdk.token.getWithoutPrompt({ | ||
responseType: responseType, | ||
scopes: token.scopes | ||
}) | ||
.then(function(freshToken) { | ||
tokenMgmtRef.emitter.emit('refreshed', key, freshToken, token); | ||
add(sdk, tokenMgmtRef, storage, key, freshToken); | ||
refreshDeferred.resolve(freshToken); | ||
}) | ||
.fail(function(err) { | ||
if (err.name === 'OAuthError') { | ||
remove(tokenMgmtRef, storage, key); | ||
emitExpired(tokenMgmtRef, key, token); | ||
} | ||
refreshDeferred.reject(err); | ||
}) | ||
.fin(function() { | ||
// Remove first refresh from the queue | ||
tokenMgmtRef.refreshQueue.shift(); | ||
// Run next refresh if one exists | ||
if (tokenMgmtRef.refreshQueue[0]) { | ||
tokenMgmtRef.refreshQueue[0](); | ||
} | ||
}); | ||
} | ||
tokenMgmtRef.refreshQueue.push(tokenRefreshWithoutPrompt); | ||
if (tokenMgmtRef.refreshQueue.length === 1) { | ||
tokenRefreshWithoutPrompt(); | ||
} | ||
return refreshDeferred.promise; | ||
return sdk.token.refresh(token) | ||
.then(function(freshToken) { | ||
add(sdk, tokenMgmtRef, storage, key, freshToken); | ||
tokenMgmtRef.emitter.emit('refreshed', key, freshToken, token); | ||
return freshToken; | ||
}) | ||
.fail(function(err) { | ||
if (err.name === 'OAuthError') { | ||
remove(tokenMgmtRef, storage, key); | ||
emitExpired(tokenMgmtRef, key, token); | ||
} | ||
throw err; | ||
}); | ||
} | ||
@@ -199,4 +166,3 @@ | ||
autoRefresh: options.autoRefresh, | ||
refreshTimeouts: {}, | ||
refreshQueue: [] // track refreshes, because we can only refresh one at a time | ||
refreshTimeouts: {} | ||
}; | ||
@@ -203,0 +169,0 @@ |
@@ -77,2 +77,6 @@ /*! | ||
function isArray(obj) { | ||
return Object.prototype.toString.call(obj) === '[object Array]'; | ||
} | ||
function isoToUTCString(str) { | ||
@@ -199,2 +203,9 @@ var parts = str.match(/\d+/g), | ||
function deprecateWrap(text, fn) { | ||
return function() { | ||
deprecate(text); | ||
return fn.apply(null, arguments); | ||
}; | ||
} | ||
module.exports = { | ||
@@ -210,2 +221,3 @@ base64UrlToBase64: base64UrlToBase64, | ||
isNumber: isNumber, | ||
isArray: isArray, | ||
isoToUTCString: isoToUTCString, | ||
@@ -220,3 +232,4 @@ toQueryParams: toQueryParams, | ||
getLink: getLink, | ||
deprecate: deprecate | ||
deprecate: deprecate, | ||
deprecateWrap: deprecateWrap | ||
}; |
{ | ||
"name": "@okta/okta-auth-js", | ||
"description": "The Okta Auth SDK", | ||
"version": "1.4.0", | ||
"version": "1.5.0", | ||
"homepage": "https://github.com/okta/okta-auth-js", | ||
@@ -25,6 +25,5 @@ "license": "Apache-2.0", | ||
"build:tests": "webpack --config webpack.test.config.js", | ||
"package": "grunt", | ||
"ci-update-package": "./node_modules/@okta/ci-update-package/bin/ci-update-package.js", | ||
"ci-pkginfo:dataload": "./node_modules/@okta/ci-pkginfo/bin/ci-pkginfo.js -t dataload", | ||
"prepublish": "node ./writeConfig.js" | ||
"prepublish": "node ./writeConfig.js && grunt shell:UMDNoDependencies" | ||
}, | ||
@@ -66,3 +65,2 @@ "author": "Okta", | ||
"DEFAULT_MAX_CLOCK_SKEW": 300, | ||
"FRAME_ID": "okta-oauth-helper-frame", | ||
"REDIRECT_OAUTH_PARAMS_COOKIE_NAME": "okta-oauth-redirect-params", | ||
@@ -69,0 +67,0 @@ "TOKEN_STORAGE_NAME": "okta-token-storage" |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
558089
31
2118