Skip to content

Commit

Permalink
fix(authentication-client): Improve socket reauthentication handling (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
daffl authored Nov 27, 2022
1 parent cfc6c7a commit 9db5e7a
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 12 deletions.
18 changes: 6 additions & 12 deletions packages/authentication-client/src/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,18 +67,12 @@ export class AuthenticationClient {
}

handleSocket(socket: any) {
// Connection events happen on every reconnect
const connected = this.app.io ? 'connect' : 'open'
const disconnected = this.app.io ? 'disconnect' : 'disconnection'

socket.on(disconnected, () => {
const authPromise = new Promise((resolve) => socket.once(connected, (data: any) => resolve(data)))
// Only reconnect when `reAuthenticate()` or `authenticate()`
// has been called explicitly first
// Force reauthentication with the server
.then(() => (this.authenticated ? this.reAuthenticate(true) : null))

this.app.set('authentication', authPromise)
// When the socket disconnects and we are still authenticated, try to reauthenticate right away
// the websocket connection will handle timeouts and retries
socket.on('disconnect', () => {
if (this.authenticated) {
this.reAuthenticate(true)
}
})
}

Expand Down
30 changes: 30 additions & 0 deletions packages/authentication-client/test/integration/socketio.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import socketioClient from '@feathersjs/socketio-client'
import authClient from '../../src'
import getApp from './fixture'
import commonTests from './commons'
import { AuthenticationResult } from '@feathersjs/authentication/lib'

describe('@feathersjs/authentication-client Socket.io integration', () => {
let app: Application
Expand Down Expand Up @@ -52,6 +53,35 @@ describe('@feathersjs/authentication-client Socket.io integration', () => {
assert.strictEqual(dummy.headers.authorization, `Bearer ${accessToken}`)
})

it('reconnects after socket disconnection', async () => {
const user = { email: 'disconnecttest@example.com', password: 'alsosecret' }
const socket = io('http://localhost:9777', {
timeout: 500,
reconnection: true,
reconnectionDelay: 100
})
const client = feathers().configure(socketioClient(socket)).configure(authClient())

await app.service('users').create(user)
await client.authenticate({
strategy: 'local',
...user
})

const onLogin = new Promise<AuthenticationResult>((resolve) => app.once('login', (data) => resolve(data)))

socket.once('disconnect', () => socket.connect())
socket.disconnect()

const {
authentication: { strategy }
} = await onLogin
const dummy = await client.service('dummy').find()

assert.strictEqual(strategy, 'jwt')
assert.strictEqual(dummy.user.email, user.email)
})

commonTests(
() => app,
() => {
Expand Down

0 comments on commit 9db5e7a

Please sign in to comment.