{"id":16805,"library":"eazy-auth","title":"eazy-auth: Redux-based Authentication for React","description":"eazy-auth is a JavaScript library designed to streamline common authentication tasks within React applications that leverage Redux and Redux-Saga. Currently at version 0.7.1, it provides a 'battery-included' solution for token-based authentication, handling login, token refresh, logout, and user data management. It integrates a Redux reducer, Redux-Saga flows for side effects (like API calls and token refreshing), and React components/HOCs for UI integration, alongside `react-router-dom` for protecting routes. The package allows developers to define custom API calls for authentication, making it adaptable to various backend systems while abstracting away much of the boilerplate. Its pre-1.0.0 status suggests ongoing development, though the README presents it as a functional solution. There is also `use-eazy-auth` which provides similar functionality using React hooks without the strong Redux/Redux-Saga dependency.","status":"active","version":"0.7.1","language":"javascript","source_language":"en","source_url":null,"tags":["javascript","eazy","easy-auth","react","redux","authentication","redux-saga","react-auth","react-router"],"install":[{"cmd":"npm install eazy-auth","lang":"bash","label":"npm"},{"cmd":"yarn add eazy-auth","lang":"bash","label":"yarn"},{"cmd":"pnpm add eazy-auth","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Peer dependency for UI components and HOCs.","package":"react","optional":false},{"reason":"Peer dependency for Redux integration in React components.","package":"react-redux","optional":false},{"reason":"Peer dependency for `AuthRoute` component to protect routes (targets v4.1.x).","package":"react-router-dom","optional":false},{"reason":"Peer dependency for Redux store integration, specifically `makeAuthReducer`.","package":"redux","optional":false},{"reason":"Peer dependency for managing side effects, specifically `makeAuthFlow`.","package":"redux-saga","optional":false},{"reason":"Peer dependency for efficient selector creation.","package":"reselect","optional":false}],"imports":[{"note":"Used to create the authentication reducer for your Redux store.","wrong":"const makeAuthReducer = require('eazy-auth').makeAuthReducer;","symbol":"makeAuthReducer","correct":"import { makeAuthReducer } from 'eazy-auth'"},{"note":"Function to configure and retrieve `authFlow` (the main saga) and `authCall` (an authenticated saga `call` effect). Parameters (`loginCall`, `refreshTokenCall`, `meCall`) are critical for custom API integration.","wrong":"const { authFlow, authCall } = require('eazy-auth').makeAuthFlow;","symbol":"makeAuthFlow","correct":"import { makeAuthFlow } from 'eazy-auth'"},{"note":"Action creator for initiating the login process with credentials.","wrong":"import login from 'eazy-auth/actions/login';","symbol":"login","correct":"import { login } from 'eazy-auth'"},{"note":"Selector to retrieve the authenticated user object from the Redux state.","wrong":"import { selectors } from 'eazy-auth'; selectors.getAuthUser;","symbol":"getAuthUser","correct":"import { getAuthUser } from 'eazy-auth'"},{"note":"React Router component (for v4.x) to protect routes, redirecting unauthenticated users. Not compatible with React Router v6 directly.","wrong":"import AuthRoute from 'eazy-auth/components/AuthRoute';","symbol":"AuthRoute","correct":"import { AuthRoute } from 'eazy-auth'"}],"quickstart":{"code":"import React from 'react';\nimport ReactDOM from 'react-dom';\nimport { createStore, combineReducers, applyMiddleware } from 'redux';\nimport { Provider } from 'react-redux';\nimport createSagaMiddleware from 'redux-saga';\nimport { fork, call, put } from 'redux-saga/effects';\nimport { BrowserRouter as Router, Switch } from 'react-router-dom';\nimport { makeAuthReducer, makeAuthFlow, AuthRoute, login, getAuthUser } from 'eazy-auth';\n\n// 1. Redux Reducer Setup\nconst rootReducer = combineReducers({\n  auth: makeAuthReducer(),\n  // ... other reducers\n});\n\n// 2. Redux Saga Setup\nconst loginMockCall = async (credentials) => {\n  console.log('Attempting login with:', credentials);\n  if (credentials.username === 'test' && credentials.password === 'password') {\n    return { access_token: 'fake-access-token', refresh_token: 'fake-refresh-token' };\n  }\n  throw new Error('Invalid credentials');\n};\n\nconst refreshTokenMockCall = async (refreshToken) => {\n  console.log('Attempting token refresh with:', refreshToken);\n  if (refreshToken === 'fake-refresh-token') {\n    return { access_token: 'new-fake-access-token', refresh_token: 'new-fake-refresh-token' };\n  }\n  throw new Error('Invalid refresh token');\n};\n\nconst meMockCall = async (token) => {\n  console.log('Fetching user data with token:', token);\n  if (token && token.startsWith('fake-')) {\n    return { id: 'user-123', username: 'testuser', email: 'test@example.com' };\n  }\n  throw new Error('Unauthorized');\n};\n\nconst { authFlow, authCall } = makeAuthFlow({\n  loginCall: loginMockCall,\n  refreshTokenCall: refreshTokenMockCall,\n  meCall: meMockCall,\n});\n\nfunction* mainSaga() {\n  yield fork(authFlow);\n  // Example of using authCall for an authenticated API call\n  try {\n    const userData = yield authCall(async (token) => {\n      console.log('Authenticated API call with token:', token);\n      // Simulate an API call\n      return new Promise(resolve => setTimeout(() => resolve({ message: `Data for ${token}` }), 100));\n    });\n    yield put({ type: 'API_CALL_SUCCESS', payload: userData });\n  } catch (error) {\n    yield put({ type: 'API_CALL_FAILURE', error: error.message });\n  }\n}\n\nconst sagaMiddleware = createSagaMiddleware();\nconst store = createStore(rootReducer, applyMiddleware(sagaMiddleware));\nsagaMiddleware.run(mainSaga);\n\n// 3. React UI Setup\nimport { connect } from 'react-redux';\n\nconst LoginPage = ({ login, user }) => {\n  const handleSubmit = (e) => {\n    e.preventDefault();\n    login({ username: 'test', password: 'password' });\n  };\n\n  return (\n    <div>\n      <h2>Login</h2>\n      {user ? (\n        <p>Logged in as: {user.username}</p>\n      ) : (\n        <form onSubmit={handleSubmit}>\n          <button type=\"submit\">Log In (test/password)</button>\n        </form>\n      )}\n    </div>\n  );\n};\n\nconst ConnectedLoginPage = connect(\n  (state) => ({ user: getAuthUser(state) }),\n  { login }\n)(LoginPage);\n\nconst ProfilePage = ({ user }) => (\n  <div>\n    <h2>Profile</h2>\n    {user ? (\n      <p>Welcome, {user.username}!</p>\n    ) : (\n      <p>Please log in to view your profile.</p>\n    )}\n  </div>\n);\n\nconst App = () => (\n  <Provider store={store}>\n    <Router>\n      <ConnectedLoginPage />\n      <Switch>\n        <AuthRoute path=\"/profile\" component={ProfilePage} exact />\n        {/* Other routes */}\n      </Switch>\n    </Router>\n  </Provider>\n);\n\nReactDOM.render(<App />, document.getElementById('root'));\n","lang":"javascript","description":"This quickstart demonstrates the full integration of `eazy-auth` into a React, Redux, and Redux-Saga application. It sets up the Redux reducer and saga middleware, configures the `authFlow` with mock API calls for login, refresh, and user data, shows how to initiate a login, and protects a route using `AuthRoute` for authenticated users. The `authCall` effect is also demonstrated for making authenticated API requests within sagas."},"warnings":[{"fix":"Always pin exact versions of `eazy-auth` to avoid unexpected breaking changes, or carefully review release notes for any updates.","message":"The package is currently in version 0.7.1, indicating a pre-1.0.0 status. This means that API changes, including breaking changes, might occur in minor or patch releases without following strict semantic versioning, as often happens before a stable major release. Developers should review release notes carefully for updates.","severity":"breaking","affected_versions":"<1.0.0"},{"fix":"Consider alternative storage mechanisms for tokens like `sessionStorage` (for session-only persistence) or `HttpOnly` cookies, especially for highly sensitive applications. Ensure robust Content Security Policy (CSP) and input sanitization to mitigate XSS risks.","message":"`eazy-auth` stores access and refresh tokens in `localStorage` by default. While convenient for persistence across sessions, storing tokens in `localStorage` makes them vulnerable to Cross-Site Scripting (XSS) attacks. If an attacker can inject malicious JavaScript, they can steal these tokens, leading to session hijacking.","severity":"gotcha","affected_versions":">=0.1.0"},{"fix":"For applications using `react-router-dom` v6, you will need to implement your own `AuthRoute` or protected route wrapper using the new API (e.g., `useNavigate`, `Outlet`, `Navigate` components) and `eazy-auth`'s selectors to check authentication status. Alternatively, consider using `use-eazy-auth` which provides a hooks-based approach to auth.","message":"The `AuthRoute` component provided by `eazy-auth` is designed for `react-router-dom` v4.1.x. It is not directly compatible with `react-router-dom` v6 or newer versions, which introduced significant API changes to route definition and navigation.","severity":"gotcha","affected_versions":">=0.1.0"},{"fix":"Carefully ensure that your custom API call functions (`loginCall`, `refreshTokenCall`, `meCall`) adhere to the expected Promise resolution formats as described in the documentation, and handle potential API errors gracefully within those functions.","message":"The `makeAuthFlow` function requires `loginCall`, `refreshTokenCall`, and `meCall` to be asynchronous functions (returning Promises) that resolve to specific data structures (e.g., `{ access_token, refresh_token }` for login/refresh, and user data object for `meCall`). Incorrect return formats or promise rejections can lead to unexpected authentication flow failures or errors in the Redux state.","severity":"gotcha","affected_versions":">=0.1.0"}],"env_vars":null,"last_verified":"2026-04-22T00:00:00.000Z","next_check":"2026-07-21T00:00:00.000Z","problems":[{"fix":"Verify the `loginCall` function logic, ensuring it correctly handles credentials and communicates with your backend. Check network requests in the browser developer tools for API errors. Ensure the backend returns the `access_token` and `refresh_token` in the expected format.","cause":"The `loginCall` provided to `makeAuthFlow` rejected its promise due to incorrect credentials or a network issue with your authentication API.","error":"Error: Invalid credentials (or similar network error during login)"},{"fix":"Review your `loginCall` and `refreshTokenCall` implementations. Ensure they return a Promise that resolves to an object like `{ access_token: 'your_token', refresh_token: 'your_refresh_token' }`.","cause":"The `loginCall` or `refreshTokenCall` functions did not return an object with `access_token` and `refresh_token` keys as expected by `eazy-auth`.","error":"TypeError: Cannot read properties of undefined (reading 'access_token') or similar when makeAuthFlow is called"},{"fix":"If using `react-router-dom` v4 or v5, ensure `AuthRoute` is nested inside `<Switch>`. If using `react-router-dom` v6, the `AuthRoute` component from `eazy-auth` is incompatible. You will need to create a custom protected route component or use the `use-eazy-auth` library which is hooks-based.","cause":"The `AuthRoute` component is being used with `react-router-dom` v6 or later, which has a different API compared to v4.x, or it's not wrapped within a `<Routes>` (v6) or `<Switch>` (v4/5) component.","error":"React Router caught an unhandled error: You used a <Route> outside of a <Routes> context. Or 'AuthRoute' is not a <Route> component."}],"ecosystem":"npm","meta_description":null}