diff --git a/oauth3.core.js b/oauth3.core.js index f14d429..91975e8 100644 --- a/oauth3.core.js +++ b/oauth3.core.js @@ -208,14 +208,16 @@ // 'abc.qrs.xyz' // [ 'abc', 'qrs', 'xyz' ] - // [ {}, {}, 'foo' ] - // { header: {}, payload: {}, signature: '' } + // {} var parts = str.split(/\./g); - var jsons = parts.slice(0, 2).map(function (urlsafe64) { - return JSON.parse(OAUTH3._base64.decodeUrlSafe(urlsafe64)); - }); + var err; + if (parts.length !== 3) { + err = new Error("Invalid JWT: required 3 '.' separated components not "+parts.length); + err.code = 'E_INVALID_JWT'; + throw err; + } - return { header: jsons[0], payload: jsons[1] }; + return JSON.parse(OAUTH3._base64.decodeUrlSafe(parts[1])); } , verify: function (jwk, token) { var parts = token.split(/\./g); @@ -224,20 +226,27 @@ return OAUTH3.crypto.core.verify(jwk, data, signature); } - , freshness: function (tokenMeta, staletime, _now) { - staletime = staletime || (15 * 60); - var now = _now || Date.now(); - var fresh = ((parseInt(tokenMeta.exp, 10) || 0) - Math.round(now / 1000)); - - if (fresh >= staletime) { + , freshness: function (tokenMeta, staletime, now) { + // If the token doesn't expire then it's always fresh. + if (!tokenMeta.exp) { return 'fresh'; } - if (fresh <= 0) { - return 'expired'; + staletime = staletime || (15 * 60); + now = now || Date.now(); + // This particular number used to check if time is in milliseconds or seconds will work + // for any date between the years 1973 and 5138. + if (now > 1e11) { + now = Math.round(now / 1000); + } + var exp = parseInt(tokenMeta.exp, 10) || 0; + if (exp < now) { + return 'expired'; + } else if (exp < now + staletime) { + return 'stale'; + } else { + return 'fresh'; } - - return 'stale'; } } , urls: { @@ -338,29 +347,36 @@ // , "username": "<>", "password": "password" } // opts = opts || {}; - var type = 'access_token'; - var grantType = 'refresh_token'; + var refresh_token = opts.refresh_token || (opts.session && opts.session.refresh_token); + var err; + if (!refresh_token) { + err = new Error('refreshing a token requires a refresh token'); + err.code = 'E_NO_TOKEN'; + throw err; + } + if (OAUTH3.jwt.freshness(OAUTH3.jwt.decode(refresh_token)) === 'expired') { + err = new Error('refresh token has also expired, login required again'); + err.code = 'E_EXPIRED_TOKEN'; + throw err; + } var scope = opts.scope || directive.authn_scope; - var clientSecret = opts.client_secret; - var args = directive[type]; + var args = directive.access_token; var params = { - "grant_type": grantType - , "refresh_token": opts.refresh_token || (opts.session && opts.session.refresh_token) + "grant_type": 'refresh_token' + , "refresh_token": refresh_token , "response_type": 'token' , "client_id": opts.client_id || opts.client_uri , "client_uri": opts.client_uri - //, "scope": undefined - //, "client_secret": undefined , debug: opts.debug || undefined }; var uri = args.url; var body; - if (clientSecret) { + if (opts.client_secret) { // TODO not allowed in the browser console.warn("if this is a browser, you must not use client_secret"); - params.client_secret = clientSecret; + params.client_secret = opts.client_secret; } if (scope) { @@ -482,7 +498,7 @@ oldSession.client_uri = clientUri; // azp // info about the newly-discovered token - oldSession.token = OAUTH3.jwt.decode(oldSession.access_token).payload; + oldSession.token = OAUTH3.jwt.decode(oldSession.access_token); oldSession.token.sub = oldSession.token.sub || (oldSession.token.acx||{}).id @@ -493,7 +509,7 @@ oldSession.token.provider_uri = providerUri; if (oldSession.refresh_token) { - oldSession.refresh = OAUTH3.jwt.decode(oldSession.refresh_token).payload; + oldSession.refresh = OAUTH3.jwt.decode(oldSession.refresh_token); oldSession.refresh.sub = oldSession.refresh.sub || (oldSession.refresh.acx||{}).id || ((oldSession.refresh.axs||[])[0]||{}).appScopedId