Skip to content

Commit

Permalink
refresh token before expiry
Browse files Browse the repository at this point in the history
  • Loading branch information
OskarDamkjaer committed Sep 28, 2023
1 parent 9e69b8c commit b42ac7d
Showing 1 changed file with 43 additions and 0 deletions.
43 changes: 43 additions & 0 deletions src/shared/modules/connections/connectionsDuck.ts
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,47 @@ export const setAuthEnabled = (authEnabled: any) => {
}
}

function currentTokenExpiresSeconds(state: GlobalState) {
const activeConnection = getActiveConnectionData(state)
const token = activeConnection?.password

if (!token) return

// Get the expiration from the JWT's payload, which is a JSON string encoded
// using base64. You could also use a JWT parsing lib
const [, payloadBase64] = token.split('.')
const payload: { exp: number } = JSON.parse(window.atob(payloadBase64 ?? ''))

if (typeof payload?.exp !== 'number') {
return
}

return payload.exp - Date.now() / 1000
}

// Typically the refresh flow is triggered through a query failing
// with the "token expired error". We schedule a refresh to happen
// before the expiration to avoid the error.
// We still have the old flow since settimeout is not 100% reliable
export function scheduleTokenAuthTokenRefresh(store: any) {
const expiresIn = currentTokenExpiresSeconds(store.getState())
if (expiresIn) {
authLog('Schedule token refresh 60 seconds before expiration')
const refreshIn = expiresIn - 60
setTimeout(() => {
// check if the token has been refreshed or switched in the meantime
const expiresIn = currentTokenExpiresSeconds(store.getState())

if (expiresIn && expiresIn <= 60) {
authLog('Scheduled token refresh triggered')
onLostConnection(store.dispatch)({
code: TokenExpiredDriverError
})
}
}, [refreshIn * 1000])
}
}

export const useDb = (db: any = null) => ({ type: USE_DB, useDb: db })

export const resetUseDb = () => ({ type: USE_DB, useDb: null })
Expand Down Expand Up @@ -563,6 +604,7 @@ export const startupConnectEpic = (action$: any, store: any) => {
store.dispatch(setActiveConnection(discovery.CONNECTION_ID))
if (discovered.attemptSSOLogin) {
authLog('SSO Connection to Neo4j successfully established.')
scheduleTokenAuthTokenRefresh(store)
}
resolve({ type: STARTUP_CONNECTION_SUCCESS })
})
Expand Down Expand Up @@ -703,6 +745,7 @@ export const connectionLostEpic = (action$: any, store: any) =>
authLog(
'Successfully refreshed token, attempting to reconnect'
)
scheduleTokenAuthTokenRefresh(store)
} catch (e) {
authLog(`Failed to refresh token: ${e}`)
authLog(
Expand Down

0 comments on commit b42ac7d

Please sign in to comment.