Skip to content

Commit

Permalink
Handle fetch top-level errors and retry network errors
Browse files Browse the repository at this point in the history
  • Loading branch information
valeriangalliat committed Feb 28, 2023
1 parent f46d5ed commit e43259f
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 41 deletions.
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -560,6 +560,21 @@ Error handler that will be called if there's an unexpected error while refreshin

This library will **not** throw when it cannot refresh an ID token. Instead, it will provide an unauthenticated user to the app. See [#366](https://github.com/gladly-team/next-firebase-auth/issues/366) and [#174](https://github.com/gladly-team/next-firebase-auth/issues/174) for additional background.

#### fetchRetryConfig

`Object` (optional)

Configuration options for the [fetch-retry](https://www.npmjs.com/package/fetch-retry) module. Allows to customize retry behavior of calls to `loginAPIEndpoint` and `logoutAPIEndpoint`.

Example:

```js
{
retries: 5,
retryDelay: 800,
}
```

## Types

### AuthAction
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@
"dependencies": {
"@babel/runtime": "^7.18.9",
"cookies": "^0.8.0",
"fetch-retry": "^5.0.4",
"hoist-non-react-statics": "^3.3.2"
},
"files": [
Expand Down
3 changes: 3 additions & 0 deletions src/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ const defaultConfig = {
secure: true,
signed: true,
},
// Config for fetch-retry module, to customize the retry behavior of
// API login and logout requests.
fetchRetryConfig: undefined,
}

const validateConfig = (mergedConfig) => {
Expand Down
94 changes: 53 additions & 41 deletions src/useFirebaseUser.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
import { useEffect, useState } from 'react'
import { getApp } from 'firebase/app'
import { getAuth, getIdTokenResult, onIdTokenChanged } from 'firebase/auth'
import makeFetchRetry from 'fetch-retry'
import { getConfig } from 'src/config'
import createAuthUser from 'src/createAuthUser'
import { filterStandardClaims } from 'src/claims'
import logDebug from 'src/logDebug'

const fetchRetry = makeFetchRetry(fetch)

const defaultTokenChangedHandler = async (authUser) => {
const {
loginAPIEndpoint,
logoutAPIEndpoint,
onLoginRequestError,
onLogoutRequestError,
fetchRetryConfig,
} = getConfig()
let response
// If the user is authed, call login to set a cookie.
Expand All @@ -20,29 +24,33 @@ const defaultTokenChangedHandler = async (authUser) => {
// place we use this logic.
logDebug('[withAuthUser] Calling the login endpoint.')
const userToken = await authUser.getIdToken()
response = await fetch(loginAPIEndpoint, {
method: 'POST',
headers: {
Authorization: userToken,
},
credentials: 'include',
})
if (!response.ok) {
const responseJSON = await response.json()
logDebug(
`[withAuthUser] The call to the login endpoint failed with status ${
response.status
} and response: ${JSON.stringify(responseJSON)}`
)
try {
response = await fetchRetry(loginAPIEndpoint, {
method: 'POST',
headers: {
Authorization: userToken,
},
credentials: 'include',
...fetchRetryConfig,
})
if (!response.ok) {
const responseJSON = await response.json()
logDebug(
`[withAuthUser] The call to the login endpoint failed with status ${
response.status
} and response: ${JSON.stringify(responseJSON)}`
)

// If the developer provided a handler for login errors,
// call it and don't throw.
// https://github.com/gladly-team/next-firebase-auth/issues/367
const err = new Error(
`Received ${
response.status
} response from login API endpoint: ${JSON.stringify(responseJSON)}`
)
// If the developer provided a handler for login errors,
// call it and don't throw.
// https://github.com/gladly-team/next-firebase-auth/issues/367
throw new Error(
`Received ${
response.status
} response from login API endpoint: ${JSON.stringify(responseJSON)}`
)
}
} catch (err) {
if (onLoginRequestError) {
await onLoginRequestError(err)
} else {
Expand All @@ -52,26 +60,30 @@ const defaultTokenChangedHandler = async (authUser) => {
} else {
// If the user is not authed, call logout to unset the cookie.
logDebug('[withAuthUser] Calling the logout endpoint.')
response = await fetch(logoutAPIEndpoint, {
method: 'POST',
credentials: 'include',
})
if (!response.ok) {
const responseJSON = await response.json()
logDebug(
`[withAuthUser] The call to the logout endpoint failed with status ${
response.status
} and response: ${JSON.stringify(responseJSON)}`
)
try {
response = await fetchRetry(logoutAPIEndpoint, {
method: 'POST',
credentials: 'include',
...fetchRetryConfig,
})
if (!response.ok) {
const responseJSON = await response.json()
logDebug(
`[withAuthUser] The call to the logout endpoint failed with status ${
response.status
} and response: ${JSON.stringify(responseJSON)}`
)

// If the developer provided a handler for logout errors,
// call it and don't throw.
// https://github.com/gladly-team/next-firebase-auth/issues/367
const err = new Error(
`Received ${
response.status
} response from logout API endpoint: ${JSON.stringify(responseJSON)}`
)
// If the developer provided a handler for logout errors,
// call it and don't throw.
// https://github.com/gladly-team/next-firebase-auth/issues/367
throw new Error(
`Received ${
response.status
} response from logout API endpoint: ${JSON.stringify(responseJSON)}`
)
}
} catch (err) {
if (onLogoutRequestError) {
await onLogoutRequestError(err)
} else {
Expand Down
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3999,6 +3999,11 @@ fb-watchman@^2.0.0:
dependencies:
bser "2.1.1"

fetch-retry@^5.0.4:
version "5.0.4"
resolved "https://registry.yarnpkg.com/fetch-retry/-/fetch-retry-5.0.4.tgz#06e8e4533030bf6faa00ffbb9450cb9264c23c12"
integrity sha512-LXcdgpdcVedccGg0AZqg+S8lX/FCdwXD92WNZ5k5qsb0irRhSFsBOpcJt7oevyqT2/C2nEE0zSFNdBEpj3YOSw==

file-entry-cache@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027"
Expand Down

0 comments on commit e43259f

Please sign in to comment.