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

Feature request: After network reconnect - authenticate before service call retry #854

Closed
pematt opened this issue Apr 16, 2018 · 8 comments

Comments

@pematt
Copy link

pematt commented Apr 16, 2018

Steps to reproduce

My app is based on the feathers-chat-vuex repo with some modifications.

  1. Connect and authenticate using JWT
  2. Create a network outage between the client and the server
  3. Issue Feathers service call on the client (e.g.: fetch)
  4. Reinstate the network connection between the client and the server
  5. The client automatically retries the service call from step 3 and fails with 'NotAuthenticated: No auth token'
  6. The client authenticates automatically using the token from step 1

Expected behavior

Upon reconnect then automatic re-authentication should be performed before any Feathers service calls issued during the network outage are retried. I.e.: Step 6 from above should happen before step 5.

Note: I'm not good enough to find out how to fix this myself, however, if someone could point out where the change needs to be done then I'll have a go.

Actual behavior

Upon reconnect then any Feathers service calls issued during the network outage are retried before the automatic re-authentication is performed.

System configuration

Module versions (especially the part that's not working):
Client:
"dependencies": {
"@feathersjs/authentication-client": "^1.0.2",
"@feathersjs/feathers": "^3.1.4",
"@feathersjs/socketio": "^3.2.1",
"@feathersjs/socketio-client": "^1.1.0",
"@fortawesome/fontawesome": "^1.1.5",
"@fortawesome/fontawesome-free-regular": "^5.0.10",
"@fortawesome/fontawesome-free-solid": "^5.0.10",
"@fortawesome/vue-fontawesome": "0.0.22",
"bootstrap": "^4.0.0",
"bootstrap-vue": "^2.0.0-rc.6",
"browser-locale": "^1.0.3",
"feathers-vuex": "^1.1.4",
"idle-vue": "^2.0.5",
"lodash": "^4.17.5",
"moment": "^2.22.1",
"moment-timezone": "^0.5.14",
"popper.js": "^1.14.3",
"socket.io-client": "^2.1.0",
"vue": "^2.5.16",
"vue-avatar": "^2.1.3",
"vue-i18n": "^7.6.0",
"vue-multiselect": "^2.1.0",
"vue-router": "^3.0.1",
"vue-search-select": "^2.6.1",
"vuex": "^3.0.1",
"zxcvbn": "^4.4.2"
},

NodeJS version:
Server:

"engines": {
"node": ">= 6.0.0",
"npm": ">= 3.0.0"
},

"dependencies": {
"@feathersjs/authentication": "^2.1.4",
"@feathersjs/authentication-jwt": "^2.0.0",
"@feathersjs/authentication-local": "^1.1.1",
"@feathersjs/authentication-oauth2": "^1.0.3",
"@feathersjs/cli": "^3.6.1",
"@feathersjs/configuration": "^1.0.2",
"@feathersjs/errors": "^3.3.0",
"@feathersjs/express": "^1.2.1",
"@feathersjs/feathers": "^3.1.4",
"@feathersjs/socketio": "^3.2.1",
"body-parser": "^1.18.2",
"compression": "^1.7.2",
"cors": "^2.8.4",
"cron": "^1.3.0",
"feathers-authentication-hooks": "^0.1.7",
"feathers-authentication-management": "^2.0.0",
"feathers-hooks-common": "^4.11.0",
"feathers-sequelize": "^3.1.0",
"helmet": "^3.12.0",
"moment-timezone": "^0.5.14",
"passport-github": "^1.1.0",
"pg": "^7.4.1",
"retry-as-promised": "^2.3.2",
"sequelize": "^4.37.6",
"serve-favicon": "^2.5.0",
"winston": "^2.4.1"
},
"devDependencies": {
"eslint": "^4.19.1",
"mocha": "^5.1.0",
"request": "^2.85.0",
"request-promise": "^4.2.2"
}

Operating System:
Ubuntu Linux 16.04 Desktop LTS, latest updates installed.

Browser Version:
Google Chrome, latest updates installed.

React Native Version:

Module Loader:
Client:
"devDependencies": {
"autoprefixer": "^8.2.0",
"babel-core": "^6.22.1",
"babel-helper-vue-jsx-merge-props": "^2.0.3",
"babel-loader": "^7.1.4",
"babel-plugin-syntax-jsx": "^6.18.0",
"babel-plugin-transform-runtime": "^6.22.0",
"babel-plugin-transform-vue-jsx": "^3.7.0",
"babel-preset-env": "^1.3.2",
"babel-preset-stage-2": "^6.22.0",
"chalk": "^2.3.2",
"copy-webpack-plugin": "^4.5.1",
"css-loader": "^0.28.11",
"eslint": "^4.19.1",
"eslint-plugin-vue": "^4.4.0",
"extract-text-webpack-plugin": "^3.0.0",
"file-loader": "^1.1.11",
"friendly-errors-webpack-plugin": "^1.7.0",
"html-webpack-plugin": "^2.30.1",
"node-notifier": "^5.1.2",
"optimize-css-assets-webpack-plugin": "^3.2.0",
"ora": "^2.0.0",
"portfinder": "^1.0.13",
"postcss-import": "^11.1.0",
"postcss-loader": "^2.1.3",
"postcss-url": "^7.3.2",
"rimraf": "^2.6.0",
"semver": "^5.5.0",
"shelljs": "^0.8.1",
"uglifyjs-webpack-plugin": "^1.2.4",
"url-loader": "^0.6.2",
"vue-loader": "^14.2.2",
"vue-style-loader": "^4.1.0",
"vue-template-compiler": "^2.5.16",
"webpack": "^3.11.0",
"webpack-bundle-analyzer": "^2.11.1",
"webpack-dev-server": "^2.11.2",
"webpack-merge": "^4.1.2"

@daffl
Copy link
Member

daffl commented Jun 9, 2018

There seem to be several issues around this but the authentication client should authenticate on reconnection (in https://github.com/feathersjs/authentication-client/blob/master/lib/passport.js#L47).

@pematt
Copy link
Author

pematt commented Jun 10, 2018

All actions performed actually do work, the problem is in the order in which the actions are performed. The request is to have the authentication to happen before any pending service calls are retried.

At the moment the pending service calls are retried before the re-authentication, the service calls then fails with a not authenticated error. If the pending service calls would not be retried until a successful re-authentication has happened then all would work fine.

@claustres
Copy link
Contributor

As a temporary workaround maybe the authenticated event should be also raised on reconnect so that app clients will know when they can safely issue service calls again ?

Indeed as @pematt said the problem is in the order in which the actions are performed, if you app also listens to network state it has no mean to ensure its callback will be called before the Feathers reconnect callback.

@averri
Copy link

averri commented May 30, 2019

I'm facing the same issue. I have tried to create an app mixin to introduce the retry:

app.mixins.push((service, path) => {

  const retryAuthenticated = method => {
    let oldMethod = service[method]
    if (oldMethod) {
      service[method] = async (...args) => {
        try {
          return oldMethod(args)
        } catch (e) {
          if (e.name === 'NotAuthenticated') {
            await app.authenticate()
            return oldMethod(args)
          } else {
            return Promise.reject(e)
          }
        }
      }
    }
  }

  retryAuthenticated('create')
  retryAuthenticated('find')
  retryAuthenticated('get')
  retryAuthenticated('update')
  retryAuthenticated('patch')
  retryAuthenticated('delete')
})

... but I should be missing something. When running this code it gets hooks.js?e37d:102 Uncaught (in promise) TypeError: Cannot read property 'before' of undefined.

@daffl
Copy link
Member

daffl commented May 30, 2019

This has been fixed in Feathers v4 Authentication. If this is an issue you are seeing I recommend migrating to the prerelease.

@averri
Copy link

averri commented May 30, 2019

Thanks @daffl, I'm keen to see the new version in action, I have read about the new features, it's very nice. Did you mean https://crow.docs.feathersjs.com/migrating.html? The link you have posted is about the v3.

I have opened a more generic question about how to create proxies for the service methods: #1378.

@daffl
Copy link
Member

daffl commented Jun 6, 2019

Yep, sorry I meant v4. Closing since this is fixed in v4 authentication. See the Authentication API and the Migration guide for more information on how to upgrade.

@daffl daffl closed this as completed Jun 6, 2019
@pematt
Copy link
Author

pematt commented Jun 6, 2019

Awesome! Thank you so much!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants