Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/hasura/react-check-auth
Add auth protection anywhere in your react/react-native app
https://github.com/hasura/react-check-auth
authentication npm-module react react-authentication
Last synced: 5 days ago
JSON representation
Add auth protection anywhere in your react/react-native app
- Host: GitHub
- URL: https://github.com/hasura/react-check-auth
- Owner: hasura
- License: mit
- Created: 2018-04-18T08:24:12.000Z (over 6 years ago)
- Default Branch: master
- Last Pushed: 2023-02-21T15:16:01.000Z (almost 2 years ago)
- Last Synced: 2024-04-14T11:41:36.701Z (8 months ago)
- Topics: authentication, npm-module, react, react-authentication
- Language: JavaScript
- Homepage:
- Size: 445 KB
- Stars: 541
- Watchers: 11
- Forks: 43
- Open Issues: 8
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
Awesome Lists containing this project
README
## react-check-auth
`react-check-auth` is a tiny react component that helps you make auth checks declarative in your react or react-native app.
This component uses [React 16's new context API](https://reactjs.org/docs/context.html) and is just ~100 LOC. It can also serve as a boilerplate for getting familiar with using the context API to pass information from a parent component to arbitrarily deep child components.
## Motivation
In a typical app UI, depending on whether the user logs in, components in the application display different information.
For example, a "welcome user" label or a "login button" on a header. Or using this information with routing, `/home` should redirect to `/login` if the user is not logged in, and `/login` should redirect to `/home` if the user is logged in.
### Before `react-check-auth`
1. On load, your app must make a request to some kind of a `/verifyUser` or a `/fetchUser` endpoint to check if the existing persisted token/cookie is available and valid.
2. You need to store that information in app state and pass it as a prop all through your component tree just so that that child components can access it or use `redux` to store the state and `connect()` the consuming component.### After `react-check-auth`
1. You specify the `authUrl` endpoint as a prop to a wrapper component called `` that has the latest props.
You don't need to make an API request, or pass props around, or manage state/reducers/connections in your app.
## Example
### 1) Add AuthProvider
Wrap your react app in a `AuthProvider` component that has an endpoint to fetch basic user information. This works because if the user had logged in, a cookie would already be present. For using authorization headers, check the docs after the examples.
```javascript
import React from "react";
import ReactDOM from "react-dom";import {AuthProvider} from "react-check-auth";
import {Header, Main} from "./components";const App = () => (
// The rest of your react app goes here
);ReactDOM.render(, document.getElementById("root"));
```### 2) Show a "welcome user" or a Login button
Now, in any arbitrary component, like a Header, you can check if the user is currently logged in. Typically you would use this for either showing a "welcome" label or a login button.
``` javascript
import {AuthConsumer} from 'react-check-auth';const Header = () => (
// Use the AuthConsumer component to check
// if userInfo is available
{({userInfo, isLoading, error}) => (
userInfo ?
(Hi {userInfo.username}) :
(Login)
)}
);
```### 3) Redirect not-logged in users to /login
You can mix and match `react-check-auth` with other declarative components like routing:
``` javascript
import {AuthConsumer} from 'react-check-auth';const Main = () => (
);
const Home = () => {
return (
{({userInfo}) => {// Redirect the user to login if they are not logged in
if (!userInfo) {
return ();
}
// Otherwise render the normal component
else {
return (Welcome Home!);
}
}}
);
}
);
```## Usage guide
### I. Backend requirements
These are the backend requirements that are assumed by `react-check-auth`.
#### 1) API endpoint to return user information
An API request to fetch user information. It should take a cookie, or a header or a body for current session information.
For example:
```http
GET https://my-backend.com/api/user
Content-Type: application/json
Cookie: <...>
Authorization: Bearer <...>
```#### 2) Success or logged-in response
If the user is logged in, the API should return a `200` status code with a `JSON` object.
For example:
```json
{
"username": "iamuser",
"id": 123
}
```#### 3) Not logged-in response
If the user is not logged-in, the API should return a **non `200`** status code:
For example:
```http
Status: 403
```### II. Installation
``` bash
$ npm install --save react-check-auth
```### III. Set up `AuthProvider`
The `AuthProvider` component should be at the top of the component tree so that any other component in the app can consume the `userInfo` information.
The `AuthProvider` takes a required prop called `authUrl` and an optional prop called `reqOptions`.
```javascript
```
##### `authUrl` :: String
Should be a valid HTTP endpoint. Can be an HTTP endpoint of any method.##### `reqOptions` :: Object || Function
Should be or return a valid `fetch` options object as per https://github.github.io/fetch/#options.**Note: This is an optional prop that does not need to be specified if your `authUrl` endpoint is a GET endpoint that accepts cookies.**
Default value that ensures cookies get sent to a `GET` endpoint:
```json
{
"method": "GET",
"credentials": "include",
"headers": {
"Content-Type": "application/json"
},
}
```#### Example 1: Use a GET endpoint with cookies
``` javascript
import React from 'react';
import {AuthProvider} from 'react-check-auth';const authUrl = "https://my-backend.com/verifyAuth";
const App = () => (
// The rest of your app goes here
);
```#### Example 2: Use a GET endpoint with a header
``` javascript
import React from 'react';
import {AuthProvider} from 'react-check-auth';const authUrl = "https://my-backend.com/verifyAuth";
const reqOptions = {
'method': 'GET',
'headers': {
'Content-Type': 'application/json',
'Authorization' : 'Bearer ' + window.localStorage.myAuthToken
},
};
const App = () => (
// The rest of your app goes here
);
```#### Example 3: Use a POST endpoint with updated token
``` javascript
import React from 'react';
import {AuthProvider} from 'react-check-auth';const authUrl = "https://my-backend.com/verifyAuth";
const reqOptions = () => {
'method': 'POST',
'headers': {
'Content-Type': 'application/json',
'Authorization' : 'Bearer ' + window.localStorage.myAuthToken
},
};
const App = () => (
// The rest of your app goes here
);
```### IV. Consuming auth state with ``
Any react component or element can be wrapped with an `` to consume the latest contextValue. You must write your react code inside a function that accepts the latest contextValue. Whenver the contextValue is updated then the AuthComponent is automatically re-rendered.
For example,
```javascript{(props) => {
props.userInfo = {..} // returned by the API
props.isLoading = true/false // if the API has not returned yet
props.error = {..} // if the API returned a non-200 or the API call failed
}}```
##### `props.userInfo` :: JSON
If the API call returned a 200 meaning that the current session is valid, `userInfo` contains as returned by the API.
If the API call returned a non-200 meaning that the current session is absent or invalid, `userInfo` is set to `null`.
##### `props.isLoading` :: Boolean
If the API call has not returned yet, `isLoading: true`. If the API call has not been made yet, or has completed then `isLoading: false`.
##### `props.error` :: JSON
If the API call returned a non-200 or there was an error in making the API call itself, `error` contains the parsed JSON value.
### V. Refresh state (eg: logout)
If you implement a logout action in your app, the auth state needs to be updated. All you need to do is call the `refreshAuth()` function available as an argument in the renderProp function of the `AuthConsumer` component.
For example:
```javascript{(refreshAuth) => (
refreshAuth()
);
}}>
Logout
```This will re-run the call to `authUrl` and update all the child components accordingly.
### VI. Using with React Native
Usage with React Native is exactly the same as with React. However you would typically use a Authorization header instead of cookies. Here's a quick example:
``` javascript
import { AuthProvider, AuthConsumer } from 'react-vksci123';
export default class App extends Component {
render() {
const sessionToken = AsyncStorage.getItem("@mytokenkey");
const reqOptions = {
"method": "GET",
"headers": sessionToken ? { "Authorization" : `Bearer ${sessionToken}` } : {}
}
return (
Welcome to React Native!
{({isLoading, userInfo, error}) => {
if (isLoading) {
return ();
}
if (error) {
return ( Unexpected );
}
if (!userInfo) {
return ();
}
return ();
}}
);
}
}```
## Plug-n-play with existing auth providers
All Auth backend providers provide an endpoint to verify a "session" and fetch user information. This component was motivated from creating documentation for integrating Hasura's auth backend into a react app with minimum boilerplate. That said this package is meant to be used with any auth provider, including your own.
### Hasura
Hasura's Auth API can be integrated with this module with a simple auth get endpoint and can also be used to redirect the user to Hasura's Auth UI Kit in case the user is not logged in.
```javascript
// replace CLUSTER_NAME with your Hasura cluster name.
const authEndpoint = 'https://auth.CLUSTER_NAME.hasura-app.io/v1/user/info';// pass the above reqObject to CheckAuth
{ ({ isLoading, userInfo, error }) => {
// your implementation here
} }
```Read the docs here.
### Firebase
`CheckAuth` can be integrated with Firebase APIs.
```javascript
// replace API_KEY with your Firebase API Key and ID_TOKEN appropriately.
const authUrl = 'https://www.googleapis.com/identitytoolkit/v3/relyingparty/getAccountInfo?key=[API_KEY]';
const reqObject = { 'method': 'POST', 'payload': {'idToken': '[ID_TOKEN]'}, 'headers': {'content-type': 'application/json'}};// pass the above reqObject to CheckAuth
{ ({ isLoading, userInfo, error }) => {
// your implementation here
} }
```### Custom Provider
`CheckAuth` can be integrated with any custom authentication provider APIs.
Lets assume we have an endpoint on the backend `/api/check_token` which reads a header `x-access-token` from the request and provides with the associated user information
```javascript
const authEndpoint = 'http://localhost:8080/api/check_token';
const reqOptions = {
'method': 'GET',
'headers': {
'Content-Type': 'application/json',
'x-access-token': 'jwt_token'
}
};
{ ( { isLoading, userInfo, error, refreshAuth }) => {
if ( !userInfo ) {
return (
Please login
);
}
return (
Hello { userInfo ? userInfo.username.name : '' }
);
}}
```It will render as `Please login` if the user's token is invalid and if the token is a valid one it will render Hello username
## How it works
![How it works](./how-it-works.png?raw=true)
1. The `AuthProvider` component uses the `authUrl` and `reqOptions` information given to it to make an API call
2. While the API call is being made, it sets the context value to have `isLoading` to `true`.
```json
{
"userInfo": null,
"isLoading": true,
"error": null
}
```
3. Once the API call returns, in the context value `isLoading` is set to `false' and:
4. Once the API call returns, if the user is logged in, the AuthProvider sets the context to `userInfo: `
```json
{
"userInfo": ,
"isLoading": false,
"error": null
}
```
5. If the user is not logged in, in the context value, `userInfo` is set to `null` and `error` is set to the error response sent by the API, if the error is in JSON.
```json
{
"userInfo": null,
"isLoading": false,
"error":
}
```
6. If the API call fails for some other reason, `error` contains the information```json
{
"userInfo": null,
"isLoading": false,
"error":
}
```
7. Whenever the contextValue is updated, any component that is wrapped with `AuthConsumer` will be re-rendered with the contextValue passed to it as an argument in the renderProp function:```javascript
{ ({userInfo, isLoading, error}) => {
return (...);
}}```
## Contributing
Clone repo
````
git clone https://github.com/hasura/react-check-auth.git
````Install dependencies
`npm install` or `yarn install`
Start development server
`npm start` or `yarn start`
Runs the demo app in development mode.
Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
#### Source code
The source code for the react components are located inside `src/lib`.
#### Demo app
A demo-app is located inside `src/demo` directory, which you can use to test your library while developing.
#### Testing
`npm run test` or `yarn run test`
#### Build library
`npm run build` or `yarn run build`
Produces production version of library under the `build` folder.
## Maintainers
This project has come out of the work at [hasura.io](https://hasura.io).
Current maintainers [@Praveen](https://twitter.com/praveenweb), [@Karthik](https://twitter.com/k_rthik1991), [@Rishi](https://twitter.com/_rishichandra).