{"id":49159,"library":"refresh-fetch","title":"refresh-fetch","description":"A wrapper around the fetch API that automatically handles authentication token refreshing. Current stable version is 0.9.0. It intercepts fetch responses, detects token expiry via a configurable `shouldRefreshToken` callback, performs token refresh via a `refreshToken` function, and retries the original request. Unlike manual token management, refresh-fetch abstracts the retry logic and ensures concurrent requests are serialized during token refresh. Requires ES6 Promise and fetch. Suitable for single-page apps using bearer tokens with expiry.","status":"active","version":"0.9.0","language":"javascript","source_language":"en","source_url":"https://github.com/vlki/refresh-fetch","tags":["javascript","api","fetch","auth","token","refresh"],"install":[{"cmd":"npm install refresh-fetch","lang":"bash","label":"npm"},{"cmd":"yarn add refresh-fetch","lang":"bash","label":"yarn"},{"cmd":"pnpm add refresh-fetch","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"native fetch API is required as a peer dependency","package":"fetch","optional":true}],"imports":[{"note":"The library is ESM-only; named export must be destructured. No default export.","wrong":"const refreshFetch = require('refresh-fetch'); const { configureRefreshFetch } = refreshFetch","symbol":"configureRefreshFetch","correct":"import { configureRefreshFetch } from 'refresh-fetch'"},{"note":"fetchJSON is a named export, not default. Used for convenience to parse JSON responses.","wrong":"import fetchJSON from 'refresh-fetch'","symbol":"fetchJSON","correct":"import { fetchJSON } from 'refresh-fetch'"},{"note":"Types are exported alongside the function; you can import them as type-only for cleaner transpilation.","wrong":"import { configureRefreshFetch, RefreshFetchConfig } from 'refresh-fetch'","symbol":"configureRefreshFetch (TypeScript)","correct":"import type { RefreshFetchConfig, RefreshFetch } from 'refresh-fetch'; import { configureRefreshFetch } from 'refresh-fetch'"}],"quickstart":{"code":"import { configureRefreshFetch, fetchJSON } from 'refresh-fetch';\n\nconst fetch = configureRefreshFetch({\n  fetch: fetchJSON,\n  shouldRefreshToken: error => error.response?.status === 401,\n  refreshToken: () => fetchJSON('/auth/refresh', { method: 'POST' }).then(() => {}),\n});\n\nfetch('https://api.example.com/data')\n  .then(({ response, body }) => console.log('Success:', body))\n  .catch(error => console.error('Error:', error));","lang":"javascript","description":"Demonstrates configuring refresh-fetch with fetchJSON, handling 401 errors, and making a request."},"warnings":[{"fix":"Change import from `import fetchJSON from 'refresh-fetch'` to `import { fetchJSON } from 'refresh-fetch'`","message":"fetchJSON is no longer a default export; it must be imported as a named export","severity":"breaking","affected_versions":">=0.6.0"},{"fix":"Rename `retryToken` to `refreshToken` in configuration","message":"The `retryToken` option was deprecated in favor of `refreshToken`","severity":"deprecated","affected_versions":">=0.5.0 <0.6.0"},{"fix":"Always use the returned function for authenticated requests; do not call original fetch","message":"configureRefreshFetch returns a new function, so the original fetch is unchanged and can still be used directly","severity":"gotcha","affected_versions":"all"},{"fix":"Always attach a .catch handler to avoid unhandled promise rejections","message":"All errors are passed through to the catch chain; the library does not swallow errors","severity":"gotcha","affected_versions":"all"}],"env_vars":null,"search_vec":"'0.9.0':20 'abstract':52 'api':9,82 'app':75 'around':6 'auth':84 'authent':13 'automat':11 'bearer':77 'callback':32 'concurr':58 'configur':30 'current':16 'detect':25 'ensur':57 'es6':66 'expiri':27,80 'fetch':3,8,23,51,69,83 'function':39 'handl':12 'intercept':22 'javascript':81 'logic':55 'manag':48 'manual':46 'origin':43 'page':74 'perform':33 'promis':67 'refresh':2,15,35,50,64,86 'refresh-fetch':1,49 'refreshtoken':38 'request':44,59 'requir':65 'respons':24 'retri':41,54 'serial':61 'shouldrefreshtoken':31 'singl':73 'single-pag':72 'stabl':17 'suitabl':70 'token':14,26,34,47,63,78,85 'unlik':45 'use':76 'version':18 'via':28,36 'wrapper':5","created_at":"2026-06-07T17:00:21.164354+00:00","updated_at":"2026-06-07T17:00:21.164354+00:00","problems":[{"fix":"Pass a fetch polyfill like node-fetch: `import fetch from 'node-fetch'; const rf = configureRefreshFetch({ fetch, ... })`","cause":"configureRefreshFetch requires fetch to be passed as an option, but Node.js versions <18 do not have global fetch","error":"Uncaught TypeError: fetch is not a function"},{"fix":"Use optional chaining: `error.response?.status === 401`","cause":"shouldRefreshToken callback receives a non-standard error object; if error.response is undefined, accessing status fails","error":"TypeError: Cannot destructure property 'response' of 'error' as it is undefined."},{"fix":"Pass `window.fetch.bind(window)` or use an arrow function wrapper `(url, opts) => fetch(url, opts)`","cause":"The fetch function passed may be bound to window; when used internally as a reference, the context is lost","error":"Failed to execute 'fetch' on 'Window': Illegal invocation"}],"ecosystem":"npm","meta_description":null,"install_score":null,"quickstart_score":null,"quickstart_tag":null,"pypi_latest":null,"cli_name":null,"cli_version":null,"type":"library","homepage":"https://github.com/vlki/refresh-fetch","github":"https://github.com/vlki/refresh-fetch","docs":null,"changelog":null,"pypi":null,"npm":"refresh-fetch","openapi_spec":null,"status_page":null,"smithery":null,"categories":["security"],"base_url":null,"auth_type":null,"provenance":{"verified_status":null,"verified_at":null,"last_verified":"2026-06-07","next_check":"2026-09-05","install_tag":null}}