oidc-client
Advanced tools
Comparing version 1.0.0-beta.2 to 1.0.0-beta.3
{ | ||
"name": "oidc-client", | ||
"version": "1.0.0-beta.2", | ||
"version": "1.0.0-beta.3", | ||
"description": "OpenID Connect (OIDC) & OAuth2 client library", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -5,5 +5,4 @@ // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. | ||
import Log from './Log'; | ||
import UrlUtility from './UrlUtility'; | ||
export default class ErrorResponse { | ||
export default class ErrorResponse extends Error { | ||
constructor({error, error_description, error_uri, state}={} | ||
@@ -16,5 +15,5 @@ ) { | ||
this.message = error_description || error; | ||
super(error_description || error); | ||
this.name = "ErrorResponse"; | ||
this.stack = (new Error()).stack; | ||
@@ -27,2 +26,2 @@ this.error = error; | ||
} | ||
} | ||
} |
@@ -55,2 +55,7 @@ // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. | ||
} | ||
getCheckSessionIframe() { | ||
Log.info("MetadataService.getCheckSessionIframe"); | ||
return this._getMetadataProperty("check_session_iframe"); | ||
} | ||
@@ -57,0 +62,0 @@ getEndSessionEndpoint() { |
@@ -7,2 +7,3 @@ // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. | ||
import MetadataService from './MetadataService'; | ||
import ErrorResponse from './ErrorResponse'; | ||
import SigninRequest from './SigninRequest'; | ||
@@ -18,7 +19,7 @@ import SigninResponse from './SigninResponse'; | ||
constructor(settings, { | ||
stateStore = new WebStorageStateStore(), | ||
stateStore = new WebStorageStateStore(), | ||
ResponseValidatorCtor = ResponseValidator, | ||
MetadataServiceCtor = MetadataService | ||
} = {}){ | ||
if (settings instanceof OidcClientSettings){ | ||
} = {}) { | ||
if (settings instanceof OidcClientSettings) { | ||
this._settings = settings; | ||
@@ -33,16 +34,18 @@ } | ||
} | ||
get settings() { | ||
return this._settings; | ||
} | ||
get metadataService() { | ||
return this._metadataService; | ||
} | ||
createSigninRequest({ | ||
response_type, scope, redirect_uri, data, | ||
prompt, display, max_age, ui_locales, id_token_hint, login_hint, acr_values}={}, | ||
response_type, scope, redirect_uri, data, | ||
prompt, display, max_age, ui_locales, id_token_hint, login_hint, acr_values} = {}, | ||
stateStore | ||
) { | ||
Log.info("OidcClient.createSigninRequest"); | ||
stateStore = stateStore || this._stateStore; | ||
let client_id = this._settings.client_id; | ||
@@ -52,7 +55,7 @@ response_type = response_type || this._settings.response_type; | ||
redirect_uri = redirect_uri || this._settings.redirect_uri; | ||
// id_token_hint, login_hint aren't allowed on _settings | ||
prompt = prompt || this._settings.prompt; | ||
display = display || this._settings.display; | ||
max_age = max_age || this._settings.max_age ; | ||
max_age = max_age || this._settings.max_age; | ||
ui_locales = ui_locales || this._settings.ui_locales; | ||
@@ -63,4 +66,5 @@ acr_values = acr_values || this._settings.acr_values; | ||
Log.info("Received authorization endpoint", url); | ||
let request = new SigninRequest({url, | ||
let request = new SigninRequest({ | ||
url, | ||
client_id, | ||
@@ -73,6 +77,7 @@ redirect_uri, | ||
}); | ||
var state = request.state; | ||
return stateStore.set(state.id, state.toStorageString()).then(()=>{ | ||
stateStore = stateStore || this._stateStore; | ||
return stateStore.set(state.id, state.toStorageString()).then(() => { | ||
return request; | ||
@@ -82,9 +87,8 @@ }); | ||
} | ||
processSigninResponse(url, stateStore){ | ||
processSigninResponse(url, stateStore) { | ||
Log.info("OidcClient.processSigninResponse"); | ||
var response = new SigninResponse(url); | ||
stateStore = stateStore || this._stateStore; | ||
var response = new SigninResponse(url); | ||
if (!response.state) { | ||
@@ -94,13 +98,13 @@ Log.error("No state in response"); | ||
} | ||
stateStore = stateStore || this._stateStore; | ||
var stateKey = response.state; | ||
return stateStore.remove(stateKey).then(storedStateString => { | ||
if (!storedStateString){ | ||
return stateStore.remove(response.state).then(storedStateString => { | ||
if (!storedStateString) { | ||
Log.error("No matching state found in storage"); | ||
throw new Error("No matching state found in storage"); | ||
} | ||
let state = State.fromStorageString(storedStateString); | ||
Log.info("Received state from storage; validating response"); | ||
@@ -110,16 +114,15 @@ return this._validator.validateSigninResponse(state, response); | ||
} | ||
createSignoutRequest({id_token_hint, data, post_logout_redirect_uri}={}, | ||
createSignoutRequest({id_token_hint, data, post_logout_redirect_uri} = {}, | ||
stateStore | ||
){ | ||
) { | ||
Log.info("OidcClient.createSignoutRequest"); | ||
stateStore = stateStore || this._stateStore; | ||
post_logout_redirect_uri = post_logout_redirect_uri || this._settings.post_logout_redirect_uri; | ||
return this._metadataService.getEndSessionEndpoint().then(url => { | ||
Log.info("Received end session endpoint", url); | ||
let request = new SignoutRequest({url, | ||
let request = new SignoutRequest({ | ||
url, | ||
id_token_hint, | ||
@@ -129,5 +132,10 @@ post_logout_redirect_uri, | ||
}); | ||
var state = request.state; | ||
stateStore.set(state.id, state.toStorageString()); | ||
if (state) { | ||
Log.info("Signout request has state to persist"); | ||
stateStore = stateStore || this._stateStore; | ||
stateStore.set(state.id, state.toStorageString()); | ||
} | ||
@@ -137,24 +145,30 @@ return request; | ||
} | ||
processSignoutResponse(url, stateStore){ | ||
processSignoutResponse(url, stateStore) { | ||
Log.info("OidcClient.processSignoutResponse"); | ||
stateStore = stateStore || this._stateStore; | ||
var response = new SignoutResponse(url); | ||
if (!response.state) { | ||
Log.error("No state in response"); | ||
return Promise.reject(new Error("No state in response")); | ||
Log.info("No state in response"); | ||
if (response.error) { | ||
Log.warn("Response was error", response.error); | ||
return Promise.reject(new ErrorResponse(response)); | ||
} | ||
return Promise.resolve(response); | ||
} | ||
var stateKey = response.state; | ||
stateStore = stateStore || this._stateStore; | ||
return stateStore.remove(stateKey).then(storedStateString => { | ||
if (!storedStateString){ | ||
if (!storedStateString) { | ||
Log.error("No matching state found in storage"); | ||
throw new Error("No matching state found in storage"); | ||
} | ||
let state = State.fromStorageString(storedStateString); | ||
Log.info("Received state from storage; validating response"); | ||
@@ -164,10 +178,10 @@ return this._validator.validateSignoutResponse(state, response); | ||
} | ||
clearStaleState(stateStore){ | ||
clearStaleState(stateStore) { | ||
Log.info("OidcClient.clearStaleState"); | ||
stateStore = stateStore || this._stateStore; | ||
return State.clearStaleState(stateStore, this.settings.staleStateAge); | ||
} | ||
} |
@@ -7,2 +7,3 @@ // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. | ||
import UserInfoService from './UserInfoService'; | ||
import ErrorResponse from './ErrorResponse'; | ||
import JwtUtil from './JwtUtil'; | ||
@@ -57,5 +58,5 @@ | ||
Log.warn("Response was error", response.error); | ||
return Promise.reject(response); | ||
return Promise.reject(new ErrorResponse(response)); | ||
} | ||
return Promise.resolve(response); | ||
@@ -80,3 +81,3 @@ } | ||
Log.warn("Response was error", response.error); | ||
return Promise.reject(response); | ||
return Promise.reject(new ErrorResponse(response)); | ||
} | ||
@@ -100,17 +101,24 @@ | ||
response.profile = this._filterProtocolClaims(response.profile); | ||
if (response.isOpenIdConnect) { | ||
Log.info("response is OIDC, processing claims"); | ||
if (this._settings.loadUserInfo && response.access_token && response.isOpenIdConnect) { | ||
response.profile = this._filterProtocolClaims(response.profile); | ||
if (this._settings.loadUserInfo && response.access_token) { | ||
Log.info("loading user info"); | ||
return this._userInfoService.getClaims(response.access_token).then(claims => { | ||
Log.info("loading user info"); | ||
return this._userInfoService.getClaims(response.access_token).then(claims => { | ||
response.profile = this._mergeClaims(response.profile, claims); | ||
Log.info("user info claims received, updated profile:", response.profile); | ||
response.profile = this._mergeClaims(response.profile, claims); | ||
Log.info("user info claims received, updated profile:", response.profile); | ||
return response; | ||
}); | ||
return response; | ||
}); | ||
} | ||
else { | ||
Log.info("not loading user info"); | ||
} | ||
} | ||
else { | ||
Log.info("not loading user info"); | ||
Log.info("response is not OIDC, not processing claims"); | ||
} | ||
@@ -206,4 +214,4 @@ | ||
} | ||
if (state.nonce !== jwt.payload.nonce){ | ||
if (state.nonce !== jwt.payload.nonce) { | ||
Log.error("Invalid nonce in id_token"); | ||
@@ -229,7 +237,7 @@ return Promise.reject(new Error("Invalid nonce in id_token")); | ||
return this._metadataService.getSigningKeys().then(keys => { | ||
if (!keys){ | ||
if (!keys) { | ||
Log.error("No signing keys from metadata"); | ||
return Promise.reject(new Error("No signing keys from metadata")); | ||
} | ||
Log.info("Received signing keys"); | ||
@@ -236,0 +244,0 @@ |
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved. | ||
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. | ||
import Log from './Log'; | ||
import UrlUtility from './UrlUtility'; | ||
import ErrorResponse from './ErrorResponse'; | ||
@@ -15,6 +13,6 @@ const OidcScope = "openid"; | ||
if (values.error) { | ||
return new ErrorResponse(values); | ||
} | ||
this.error = values.error; | ||
this.error_description = values.error_description; | ||
this.error_uri = values.error_uri; | ||
this.state = values.state; | ||
@@ -21,0 +19,0 @@ this.id_token = values.id_token; |
@@ -15,5 +15,7 @@ // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. | ||
this.state = new State({ data }); | ||
if (data) { | ||
this.state = new State({ data }); | ||
url = UrlUtility.addQueryParam(url, "state", this.state.id); | ||
} | ||
url = UrlUtility.addQueryParam(url, "state", this.state.id); | ||
if (id_token_hint) { | ||
@@ -20,0 +22,0 @@ url = UrlUtility.addQueryParam(url, "id_token_hint", id_token_hint); |
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved. | ||
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. | ||
import Log from './Log'; | ||
import UrlUtility from './UrlUtility'; | ||
import ErrorResponse from './ErrorResponse'; | ||
export default class SignoutResponse { | ||
constructor(url) { | ||
var values = UrlUtility.parseUrlFragment(url, "?"); | ||
if (values.error){ | ||
return new ErrorResponse(values); | ||
} | ||
this.error = values.error; | ||
this.error_description = values.error_description; | ||
this.error_uri = values.error_uri; | ||
this.state = values.state; | ||
} | ||
} |
@@ -8,21 +8,21 @@ // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. | ||
export default class State { | ||
constructor({id, nonce, data, created}={}) { | ||
constructor({id, nonce, data, created} = {}) { | ||
this._id = id || random(); | ||
this._data = data; | ||
if (nonce === true){ | ||
if (nonce === true) { | ||
this._nonce = random(); | ||
} | ||
else if (nonce){ | ||
else if (nonce) { | ||
this._nonce = nonce; | ||
} | ||
if (typeof created === 'number' && created > 0) { | ||
this._created = created; | ||
this._created = created; | ||
} | ||
else { | ||
this._created = parseInt(Date.now() / 1000); | ||
this._created = parseInt(Date.now() / 1000); | ||
} | ||
} | ||
get id() { | ||
@@ -44,35 +44,53 @@ return this._id; | ||
return JSON.stringify({ | ||
id:this.id, | ||
nonce:this.nonce, | ||
data:this.data, | ||
created:this.created | ||
id: this.id, | ||
nonce: this.nonce, | ||
data: this.data, | ||
created: this.created | ||
}); | ||
} | ||
static fromStorageString(storageString){ | ||
static fromStorageString(storageString) { | ||
Log.info("State.fromStorageString"); | ||
return new State(JSON.parse(storageString)); | ||
} | ||
static clearStaleState(storage, age){ | ||
static clearStaleState(storage, age) { | ||
Log.info("State.clearStaleState"); | ||
var cutoff = Date.now()/1000 - age; | ||
var cutoff = Date.now() / 1000 - age; | ||
return storage.getAllKeys().then(keys => { | ||
Log.info("got keys", keys); | ||
var promises = []; | ||
for(let key of keys){ | ||
for (let key of keys) { | ||
var p = storage.get(key).then(item => { | ||
var state = State.fromStorageString(item) | ||
Log.info("got item from key", key, state.created); | ||
if (state.created <= cutoff) { | ||
Log.info("key being removed", key); | ||
let remove = false; | ||
if (item) { | ||
try { | ||
var state = State.fromStorageString(item) | ||
Log.info("got item from key: ", key, state.created); | ||
if (state.created <= cutoff) { | ||
remove = true; | ||
} | ||
} | ||
catch (e) { | ||
Log.error("Error parsing state for key", key, e.message); | ||
remove = true; | ||
} | ||
} | ||
else { | ||
Log.info("no item in storage for key: ", key); | ||
remove = true; | ||
} | ||
if (remove) { | ||
Log.info("removed item for key: ", key); | ||
return storage.remove(key); | ||
} | ||
}); | ||
promises.push(p); | ||
@@ -79,0 +97,0 @@ } |
@@ -35,3 +35,3 @@ // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. | ||
this._events = new UserManagerEvents(settings); | ||
if (this.settings.automaticSilentRenew) { | ||
@@ -75,6 +75,6 @@ Log.info("automaticSilentRenew is configured, setting up silent renew") | ||
signinPopup(data) { | ||
signinPopup(args = {}) { | ||
Log.info("UserManager.signinPopup"); | ||
let url = this.settings.popup_redirect_uri || this.settings.redirect_uri; | ||
let url = args.redirect_uri || this.settings.popup_redirect_uri || this.settings.redirect_uri; | ||
if (!url) { | ||
@@ -85,7 +85,4 @@ Log.error("No popup_redirect_uri or redirect_uri configured"); | ||
let args = { | ||
data: data, | ||
redirect_uri: url, | ||
display: "popup" | ||
}; | ||
args.redirect_uri = url; | ||
args.display = "popup"; | ||
@@ -99,6 +96,7 @@ return this._signin(args, this._popupNavigator, { startUrl: url }); | ||
signinSilent(data) { | ||
signinSilent(args = {}) { | ||
Log.info("UserManager.signinSilent"); | ||
if (!this.settings.silent_redirect_uri) { | ||
let url = args.redirect_uri || this.settings.silent_redirect_uri; | ||
if (!url) { | ||
Log.error("No silent_redirect_uri configured"); | ||
@@ -108,7 +106,5 @@ return Promise.reject(new Error("No silent_redirect_uri configured")); | ||
var args = { | ||
data: data, | ||
redirect_uri: this.settings.silent_redirect_uri, | ||
prompt: "none" | ||
}; | ||
args.redirect_uri = url; | ||
args.prompt = "none"; | ||
return this._signin(args, this._iframeNavigator); | ||
@@ -142,5 +138,5 @@ } | ||
signinRedirect(data) { | ||
signinRedirect(args) { | ||
Log.info("UserManager.signinRedirect"); | ||
return this._signinStart({ data: data }, this._redirectNavigator); | ||
return this._signinStart(args, this._redirectNavigator); | ||
} | ||
@@ -151,5 +147,5 @@ signinRedirectCallback(url) { | ||
} | ||
signoutRedirect(data) { | ||
signoutRedirect(args) { | ||
Log.info("UserManager.signoutRedirect"); | ||
return this._signoutStart({ data: data }, this._redirectNavigator); | ||
return this._signoutStart(args, this._redirectNavigator); | ||
} | ||
@@ -193,3 +189,3 @@ signoutRedirectCallback(url) { | ||
_signoutStart(args, navigator, navigatorParams = {}) { | ||
_signoutStart(args = {}, navigator, navigatorParams = {}) { | ||
Log.info("_signoutStart"); | ||
@@ -203,3 +199,7 @@ | ||
var id_token = user && user.id_token; | ||
var id_token = args.id_token_hint || user && user.id_token; | ||
if (id_token) { | ||
Log.info("Setting id_token into signout request"); | ||
args.id_token_hint = id_token; | ||
} | ||
@@ -206,0 +206,0 @@ return this.removeUser().then(() => { |
Sorry, the diff of this file is too big to display
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
496756
3530