Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement loading user credentials from storage #9

Closed
wants to merge 1 commit into from

Conversation

dmitrizagidulin
Copy link
Contributor

Addresses issue #8.

Implements ClientAuthOIDC.from(options) factory method, which loads
previously selected provider uri and user credentials from storage.
(.for() wasn't used as it was a reserved word).

Usage:

let auth = ClientAuthOIDC.from({})
// credentials / tokens have now been loaded from local storage

auth.currentUser()
  .then(webId => {
    // previously saved web id
  })

@dmitrizagidulin
Copy link
Contributor Author

cc @dan-f for review.

describe('login()', () => {
it('should return the current webId if one is already present', () => {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would have expected login() to log you in no matter what, especially if the provider uri does not match the provider for the current session.

*/
constructor (options = {}) {
this.window = options.window || global.window
this.store = options.store || global.localStorage

this.debug = options.debug || console.error.bind(console)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps console.info or just console.log would be more appropriate. I think console.error is more for actual runtime errors.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I'll change it to log.

* @returns {ClientAuthOIDC}
*/
static from (options) {
let store = options.store || global.localStorage
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

window.localStorage is what you want. global throws a ReferenceError in the browser.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

global gets changed to window by Webpack.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool! I didn't know that. I still think it'd be best not to write code that piggy-backs on a specific webpack feature.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No prob, I'll remove global usage.

* (typically loaded from storage)
* @param [options.redirectUri] {string} This app's callback redirect uri,
* defaults to the current window's uri.
* @param [options.debug] {Function}
*/
constructor (options = {}) {
this.window = options.window || global.window
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm confused becauseglobal isn't defined in the browser, and calling global.window in the console throws a ReferencError. Did this work when you tested it in the browser?

this.loadCurrentCredentials()
if (this.webId) {
return Promise.resolve(this.webId)
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These same three lines exist right above...?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was debating on what the best way to do this was. The idea is - it first checks this.webId, and only then tries to loadCurrentCredentials() (which potentially initializes this.webId) and retries checking it. I suppose it doesn't hurt to drop the first check, and just to always try and load the current credentials from storage. I'll change it.

// Lastly, kick off a Select Provider popup window workflow
return this.providerFromUI()
// If not available, kick off a Select Provider popup window workflow
this.selectProviderUI()
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't the return value of this be handed back to the caller?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That was my initial thought too, when I thought there was a way that this function can actually return the provider uri. Currently, though, the selectProviderUI() function just opens the Select Provider popup window, and sets up the event listeners on it.
What would you like to see as a return value - the handle to the opened popup window?

this.redirectUri = options.redirectUri
this.webId = options.webId
this.idToken = options.idToken
this.accessToken = options.accessToken
this.method = REDIRECT // only redirect is currently supported
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this isn't used anymore.

@@ -337,6 +493,7 @@ class ClientAuthOIDC {

/**
* Redirects the current window to the given uri.
*
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The return false below will never get executed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, it looks strange, doesn't it :( It has to do with some horrible browser quirk - on some browsers, the window.location.href redirect only works if you return false from that function. (See https://stackoverflow.com/a/6109823/525338 for an example)

.then(webId => {
credentials.webId = webId

this.saveCurrentCredentials(credentials)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about setCurrentCredentials?

.catch(error => {
this.clearAuthResponseFromUrl()
if (error.message === 'Cannot resolve signing key for ID Token.') {
console.log('ID Token found, but could not validate. Provider likely has changed their public keys. Please retry login.')
this.debug('ID Token found, but could not validate. Provider likely has changed their public keys. Please retry login.')
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"retry login" is a noop currently if this.webId is stored.

@dmitrizagidulin
Copy link
Contributor Author

@dan-f thank you, great feedback.

@dmitrizagidulin dmitrizagidulin deleted the load-current-user branch January 8, 2020 17:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants