{"id":26964424,"url":"https://github.com/nicklayb/react-auth-guard","last_synced_at":"2025-10-30T08:13:46.065Z","repository":{"id":34239084,"uuid":"172608539","full_name":"nicklayb/react-auth-guard","owner":"nicklayb","description":"A React context component to manage authentication","archived":false,"fork":false,"pushed_at":"2022-12-09T13:51:32.000Z","size":3315,"stargazers_count":6,"open_issues_count":20,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-15T17:38:36.249Z","etag":null,"topics":["authentication","context-api","guard","react"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nicklayb.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-02-26T00:36:18.000Z","updated_at":"2023-05-02T01:14:34.000Z","dependencies_parsed_at":"2022-07-24T18:17:08.363Z","dependency_job_id":null,"html_url":"https://github.com/nicklayb/react-auth-guard","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nicklayb%2Freact-auth-guard","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nicklayb%2Freact-auth-guard/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nicklayb%2Freact-auth-guard/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nicklayb%2Freact-auth-guard/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nicklayb","download_url":"https://codeload.github.com/nicklayb/react-auth-guard/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246948008,"owners_count":20859362,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["authentication","context-api","guard","react"],"created_at":"2025-04-03T06:31:25.867Z","updated_at":"2025-10-30T08:13:46.002Z","avatar_url":"https://github.com/nicklayb.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# react-auth-guard\n\nA React context component to provide authentication through the app. The provider is decoupled from user persistance layout. It does not use/need Redux.\n\n### Breaking changes in 0.2.0\n\n#### Persistance strategy\nThe persistance strategy used to return a raw value from the persistance. While most storage drivers will use async workflows (like `AsyncStorage`), a promise is more suitable for this use case.\n\nThat being said, if you implemented your own persistance strategy, the only change you need to do to still be compliant is to return a promise that resolves.\n\nExample:\n```js\n// Before\nlet token = null\nconst strategy = {\n  get: () =\u003e {\n    return token\n  }\n  // ...\n}\n\n// After\nlet token = null\nconst strategy = {\n  get: () =\u003e {\n    return new Promise(resolve =\u003e resolve(token))\n  }\n  // ...\n}\n```\n\n## Installation\n\nInstall the package using the following command\n\n```shell\nyarn add react-auth-guard\n//\nnpm i -s react-auth-guard\n```\n\n## Setup\n\n\"Talking is cheap show me the code\" checkout the `src/demo` folder to get example implementation.\n\n### Setup provider\n\nSetup the application provider as the following. The only required props is the `fetchUser` function which should return a Promise. That Promise is used to check the validity of the token. If it resolves, then the app is considered authenticated, otherwise the app is considered not authenticated. As an example, this function can be a redux action to get the current user object from the server and stores it the Redux store.\n\n```js\nimport fetchUser from './actions'\nimport Provider from 'react-auth-guard'\n\nconst App = () =\u003e (\n  \u003cProvider\n    fetchUser={fetchUser}\n  \u003e\n    {({ authenticating, authenticated }) =\u003e (\n      /* Render your application */\n    )}\n  \u003c/Provider\u003e\n)\n```\n\n### Handle authentication flow\n\nI like using a `\u003cLoading /\u003e` components while the API authenticates. So if you reach to the URL and have a token in your local storage, it'll show a spinner the `fetchUser` promise is either resolved or reject.\n```js\nimport fetchUser from './actions'\nimport Provider from 'react-auth-guard'\nimport NotAuthenticated from './NotAuthenticated'\nimport Authenticated from './Authenticated'\n\nconst Loading = ({ isLoading, children }) =\u003e (isLoading\n  ? \u003ch1\u003eLoading\u003c/h1\u003e\n  : children\n)\n\nconst App = () =\u003e (\n  \u003cProvider\n    fetchUser={() =\u003e new Promise(resolve =\u003e resolve())}\n    getters={authGetters}\n    onLogout={() =\u003e alert('You\\'ve been logged out')}\n    onLogin={() =\u003e alert('Welcome to the magical world of the internet')}\n    onLoginFail={() =\u003e alert('You shall not pass!')}\n  \u003e\n    {({ authenticating, authenticated }) =\u003e (\n      \u003cLoading isLoading={authenticating}\u003e\n        {\n          authenticated\n            ? \u003cAuthenticated /\u003e\n            : \u003cNotAuthenticated /\u003e\n        }\n      \u003c/Loading\u003e\n    )}\n  \u003c/Provider\u003e\n)\n```\n\n### Login the provider\n\nTo login the provider, you have to call the `updateToken` function from the render prop or the consumer (You may also use the `withAuth` higher-order components to connect the auth props).\n\nAs shown below, the auth object is provided by the `withAuth` HOC to the component.\n\n```js\nconst NotAuthenticated = ({ auth }) =\u003e {\n  const login = () =\u003e loginUser().then(({ token }) =\u003e {\n    auth.updateToken(token)\n  })\n\n  return (\n    \u003cdiv\u003e\n      \u003ch1\u003eNotAuthenticated\u003c/h1\u003e\n      \u003cbutton type=\"button\" onClick={login}\u003eLogin\u003c/button\u003e\n    \u003c/div\u003e\n  )\n}\n\nexport default withAuth(NotAuthenticated)\n```\n\n#### Using the hook\n\nThe same strategy could be achieve using the `useAuth` hook.\n\n```js\nimport { useAuth } from 'react-auth-provider'\n\nconst NotAuthenticated = () =\u003e {\n  const auth = useAuth()\n  const login = () =\u003e loginUser().then(({ token }) =\u003e {\n    auth.updateToken(token)\n  })\n\n  return (\n    \u003cdiv\u003e\n      \u003ch1\u003eNotAuthenticated\u003c/h1\u003e\n      \u003cbutton type=\"button\" onClick={login}\u003eLogin\u003c/button\u003e\n    \u003c/div\u003e\n  )\n}\n\nexport default NotAuthenticated\n```\n\n### Logout the provider\n\nThe Consumer (and the HOC) also exposes a `logout` function that clears the token from the persistance strategy and unauthenticate the provider.\n\n```js\nconst Navbar = ({ auth }) =\u003e {(\n  \u003cdiv\u003e\n    \u003cbutton type=\"button\" onClick={auth.logout}\u003eLogout\u003c/button\u003e\n  \u003c/div\u003e\n)\n\nexport default withAuth(NotAuthenticated)\n```\n\n## Props\n\n- `fetchUser`: **required** Callbacks that takes no parameter and returns a Promise.\n- `getters`: Object that helps getting things based on the provider state see [Getters](#getters)\n- `decodeToken`: Function that decodes the token. Uses `jwt-decode` as default\n- `getDecodedUserId`: Function that decodes the user id from the decoded token. By default is returns the `sub` part of the token.\n- `persistStrategy`: A persistancy strategy object. May be useful to override if you want to persist the token in `AsyncStorage` for a React-Native usecase. Defaults to a localStorage handle, refer to [Persistance strategy](#persistance-strategy) for more info.\n- `onLogout`: Callback that'll be executed when logout is fired\n- `onLogin`: Callback that'll be executed when login is successful (the `fetchUser` did resolve)\n- `onLoginFail`: Callback that'll be executed when login is failure (the `fetchUser` did reject)\n- `children`: Function that expose the render props\n\n## Render props\n\n- `token`: The persisted token\n- `authenticating`: `true` if the `fetchUser` prop is being called.\n- `authenticated`: `true` if the `fetchUser` prop has resolved\n- `userId`: Decoded user id from the token\n- `updateToken: (token: string) =\u003e void`: Updates the token persisted token for the provided one and dispatch the `fetchUser` function prop.\n- `logout: () =\u003e void`: Clears the persisted token and sets authenticated to false\n\n## Getters\n\n### Why?\nWhat makes the provider easy to use, is because he's decoupled with app state. So if you're using GraphQL or json:api compliant api. The provider don't needs to know.\n\nGetters allows you to inject function that get available in your auth provider without composing HOC or things. For instance, I used a json:api compliant app where my local user is stored in redux other entities. Without getters, I was forced to always use Redux's connect composed with `withAuth` HOC everytime I wanted to use my current user. I added a `getUser` getter to the provider which calls calls my Redux store.\n\n### How?\n\nEvery getters receive the provider state as the first parameters like the following. Let say our app really requires a way to pad the user id.\n\n```js\n\nconst authGetters = {\n  paddedId: (providerState) =\u003e providerState.userId.toString().padStart(5, '0')\n}\n\nconst Navbar = ({ auth }) =\u003e {(\n  \u003cdiv\u003e\n    \u003ch1\u003e{auth.paddedId()}\u003c/h1\u003e /* renders \"00001\" if the user id is 1 */\n    \u003cbutton type=\"button\" onClick={auth.logout}\u003eLogout\u003c/button\u003e\n  \u003c/div\u003e\n)\n\nexport default withAuth(NotAuthenticated)\n```\n\n## Persistance strategy\n\nAs said earlier, you may not want to persist the token in the localStorage. You may be working on a React-Native app that needs to store it in `AsyncStorage`.\n\nA persistance strategy is only an object that implements three functions:\n\n- `get: () =\u003e Promise\u003cvoid\u003e`: Gets the token from the persistance using a promise\n- `persist: (token: string) =\u003e void`: Persists the given token\n- `clear: () =\u003e void`: Removes the token\n\n## Flow\n\nThe provider mounts with `authenticated` to `false` and `authenticating` to `true` to load a loading screen.\n\nBy defaults, it uses the `localStorage` strategy to handle token persistancy in the `localStorage`. When the provider is mounted, the `get` method from the strategy is called to get the currently persisted token.\n\nIf a token is present (not `null`), the provider will call the `fetchUser` function which should be used as a test with the server to validate the token. The function **must** return a Promise and must resolve only if the token is valid.\n\nIf the promise resolves, `authenticated` will be true and `authenticating` will be set to false. So you may render the app as authenticated.\nIf the promise rejects, `authenticated` will be false and `authenticating` will also be set to false. The app will render not authenticated.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnicklayb%2Freact-auth-guard","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnicklayb%2Freact-auth-guard","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnicklayb%2Freact-auth-guard/lists"}