• Stars
    star
    530
  • Rank 80,710 (Top 2 %)
  • Language
    JavaScript
  • License
    MIT License
  • Created about 6 years ago
  • Updated about 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Add auth protection anywhere in your react/react-native app

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 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 <AuthProvider.
  2. You access logged-in information by wrapping your react component/element in <AuthConsumer> 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.

import React from "react";
import ReactDOM from "react-dom";

import {AuthProvider} from "react-check-auth";
import {Header, Main} from "./components";

const App = () => (
  <AuthProvider authUrl={'https://website.com/get/userInfo'}>
    <div>
      // The rest of your react app goes here
      <Header />
      <Main />
    </div>
  </AuthProvider>
);

ReactDOM.render(<App />, 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.

  import {AuthConsumer} from 'react-check-auth';

  const Header = () => (
    <div>      
      // Use the AuthConsumer component to check 
      // if userInfo is available
      <AuthConsumer> 
        {({userInfo, isLoading, error}) => ( 
          userInfo ?
            (<span>Hi {userInfo.username}</span>) :
            (<a href="/login">Login</a>)
        )}
       </AuthConsumer>
    </div>
  );

3) Redirect not-logged in users to /login

You can mix and match react-check-auth with other declarative components like routing:

  import {AuthConsumer} from 'react-check-auth';

  const Main = () => (
    <Router>
      <Route path='/home' component={Home} />
      <Route path ='/login' component={Login} />
    </Router>
   );
   
   const Home = () => {
     return (
       <AuthConsumer>
         {({userInfo}) => {

           // Redirect the user to login if they are not logged in
           if (!userInfo) {
              return (<Redirect to='/login' />);
           } 
           
           // Otherwise render the normal component
           else {
             return (<div>Welcome Home!</div>);
           }
         }}
       </AuthConsumer>
     );
   }
);

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:

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:

{
  "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:

Status: 403

II. Installation

$ 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.

<AuthProvider authUrl="https://my-backend.com/api/user" reqOptions={requestOptionsObject} />
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:

{ 
  "method": "GET",
  "credentials": "include",
  "headers": {
    "Content-Type": "application/json"
  },  
}

Example 1: Use a GET endpoint with cookies

  import React from 'react';
  import {AuthProvider} from 'react-check-auth';

  const authUrl = "https://my-backend.com/verifyAuth";
  
  const App = () => (
    <AuthProvider authUrl={authUrl}>
      // The rest of your app goes here
    </AuthProvider>
  );

Example 2: Use a GET endpoint with a header

  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 = () => (
    <AuthProvider authUrl={authUrl} reqOptions={reqOptions}>
      // The rest of your app goes here
    </AuthProvider>
  );

Example 3: Use a POST endpoint with updated token

  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 = () => (
    <AuthProvider authUrl={authUrl} reqOptions={reqOptions}>
      // The rest of your app goes here
    </AuthProvider>
  );

IV. Consuming auth state with <AuthConsumer>

Any react component or element can be wrapped with an <AuthConsumer> 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,

<AuthConsumer>
  {(props) => {
    
    props.userInfo = {..}        // <request-object> returned by the API
    props.isLoading = true/false // if the API has not returned yet
    props.error = {..}           // <error-object> if the API returned a non-200 or the API call failed
  }}
</AuthConsumer>
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:

<AuthConsumer>
  {(refreshAuth) => (
    <button onClick={{
      this.logout() // This is a promise that calls a logout API
        .then(
          () => refreshAuth()
        );
    }}>
      Logout
    </button>
</AuthConsumer>  

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:

import { AuthProvider, AuthConsumer } from 'react-vksci123';

export default class App extends Component<Props> {
  render() {
    const sessionToken = AsyncStorage.getItem("@mytokenkey");
    const reqOptions = {
      "method": "GET",
      "headers": sessionToken ? { "Authorization" : `Bearer ${sessionToken}` } : {}
    }
    return (
      <AuthProvider
        authUrl={`https://my-backend.com/api/user`}
        reqOptions={reqOptions}
      >
        <View style={styles.container}>
          <Text style={styles.welcome}>
            Welcome to React Native!
          </Text>
          <AuthConsumer>
            {({isLoading, userInfo, error}) => {
              if (isLoading) {
                return (<ActivityIndicator />);
              }
              if (error) {
                return (<Text> Unexpected </Text>);
              }
              if (!userInfo) {
                return (<LoginComponent />);
              }
              return (<HomeComponent />);
            }}
          </AuthConsumer>
        </View>
      </AuthProvider>
    );
  }
}

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.

  // 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
  <AuthProvider authUrl={authEndpoint}>
    <AuthConsumer>
    { ({ isLoading, userInfo, error }) => { 
      // your implementation here
    } }
    </AuthConsumer>
  </AuthProvider>

Read the docs here.

Firebase

CheckAuth can be integrated with Firebase APIs.

  // 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
  <AuthProvider authUrl={authUrl} reqObject={reqObject}>
    <AuthConsumer>
    { ({ isLoading, userInfo, error }) => { 
      // your implementation here
    } }
    </AuthConsumer>
  </AuthProvider>

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

  const authEndpoint = 'http://localhost:8080/api/check_token';
  const reqOptions = { 
    'method': 'GET',
    'headers': {
      'Content-Type': 'application/json',
      'x-access-token': 'jwt_token'
    }
  };

  <AuthProvider authUrl = { authEndpoint } reqOptions={ reqOptions }>
    <AuthConsumer>
      { ( { isLoading, userInfo, error, refreshAuth }) => {
        if ( !userInfo ) {
          return (
            <span>Please login</span>
          );
        }
        return (
          <span>Hello { userInfo ? userInfo.username.name : '' }</span>
        );
      }}
    </AuthConsumer>
  </AuthProvider>

It will render as <span>Please login</span> 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

  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.
{
  "userInfo": null,
  "isLoading": true,
  "error": null
}
  1. Once the API call returns, in the context value isLoading is set to `false' and:
  2. Once the API call returns, if the user is logged in, the AuthProvider sets the context to userInfo: <response-object>
{
  "userInfo": <response-object>,
  "isLoading": false,
  "error": null
}
  1. 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.
{
  "userInfo": null,
  "isLoading": false,
  "error": <error-response>
}
  1. If the API call fails for some other reason, error contains the information
{
  "userInfo": null,
  "isLoading": false,
  "error": <error-response>
}
  1. 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:
<AuthConsumer>
  { ({userInfo, isLoading, error}) => {
     return (...);
  }}
<AuthConsumer>

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 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. Current maintainers @Praveen, @Karthik, @Rishi.

More Repositories

1

graphql-engine

Blazing fast, instant realtime GraphQL APIs on your DB with fine grained access control, also trigger webhooks on database events.
TypeScript
30,844
star
2

gitkube

Build and deploy docker images to Kubernetes using git push
Go
3,758
star
3

graphqurl

curl for GraphQL with autocomplete, subscriptions and GraphiQL. Also a dead-simple universal javascript GraphQL client.
JavaScript
3,301
star
4

skor

Now part of Hasura GraphQL Engine. Listen to postgres events and forward them as JSON payloads to a webhook
C
1,247
star
5

learn-graphql

Real world GraphQL tutorials for frontend developers with deadlines!
JavaScript
1,121
star
6

gatsby-gitbook-starter

Generate GitBook style modern docs/tutorial websites using Gatsby + MDX
JavaScript
976
star
7

awesome-react-graphql

A curated collection of resources, clients and tools that make working with `GraphQL and React/React Native` awesome
735
star
8

eff

🚧 a work in progress effect system for Haskell 🚧
Haskell
530
star
9

3factor-example

Canonical example of building a 3factor app : a food ordering application
JavaScript
455
star
10

awesome-live-reloading

A curated collection of live-reloading / hot-reloading / watch-reloading tools for different languages and frameworks.
435
star
11

ra-data-hasura

react-admin data provider for Hasura GraphQL Engine
TypeScript
335
star
12

awesome-vue-graphql

A curated collection of resources, clients and tools that make working with `GraphQL and Vue.js` awesome
302
star
13

graphql-bench

A super simple tool to benchmark GraphQL queries
TSQL
256
star
14

hasura-ecommerce

TypeScript
245
star
15

pgdeltastream

Streaming Postgres logical replication changes atleast-once over websockets
Go
244
star
16

graphql-engine-heroku

Blazing fast, instant realtime GraphQL APIs on Postgres with fine grained access control, also trigger webhooks on database events.
Dockerfile
229
star
17

graphql2chartjs

graphql2chartjs reshapes your GraphQL data as per the ChartJS API.
JavaScript
222
star
18

hasura-aws-stack

A complete production ready 100% serverless stack on AWS with Hasura
JavaScript
212
star
19

json2graphql

From a JSON file to postgres-backed realtime GraphQL
JavaScript
199
star
20

3factor

3factor app is an architecture pattern for modern fullstack apps. 3factor apps are fast to build and are highly scalable.
SCSS
179
star
21

client-side-graphql

147
star
22

hasura-k8s-stack

A feature-complete Hasura stack on Kubernetes
JavaScript
138
star
23

hasura-actions-examples

Examples of handling custom business logic with Hasura Actions
JavaScript
135
star
24

awesome-angular-graphql

A curated collection of resources, clients and tools that make working with `GraphQL and Angular` awesome
132
star
25

gqless-movies-demo

A movies app using Hasura and gqless
TypeScript
127
star
26

awesome-fluent-graphql

Awesome list of fluent GraphQL clients & examples
TypeScript
103
star
27

graphiql-online

Explore your GraphQL APIs with headers
JavaScript
88
star
28

kubeformation

Create declarative cluster specifications for your managed Kubernetes vendor (GKE, AKS)
Go
86
star
29

data-dictionary

TypeScript
83
star
30

firebase2graphql

Move from Firebase realtime db to instant GraphQL APIs on Postgres
JavaScript
81
star
31

jwt-guide

TypeScript
79
star
32

nodejs-graphql-subscriptions-boilerplate

Boilerplate to setup GraphQL subscriptions in your nodejs code
JavaScript
78
star
33

graphql-serverless

Example boilerplates for GraphQL backends hosted on serverless platforms
Go
70
star
34

graphql-parser-hs

A GraphQL query parser for Haskell
Haskell
59
star
35

sphinx-graphiql

Sphinx plugin that adds a GraphiQL directive so that you can embed an interactive GraphQL query explorer in your docs
JavaScript
57
star
36

kriti-lang

A minimal JSON templating language
Haskell
53
star
37

schema-stitching-examples

JavaScript
44
star
38

gitkube-example

An example repo to be used with gitkube: git push to deploy on to Kubernetes
HTML
43
star
39

graphql-backend-benchmarks

GraphQL performance benchmarks across Hasura, Postgraphile and Prisma
Shell
42
star
40

comment-progress

Notify progress by commenting on GitHub issues, pull requests, and commits :octocat: πŸ’¬
JavaScript
38
star
41

local-development

[Deprecated] Run Hasura locally on your computer
37
star
42

rxdb-hasura-demo

An Offline first todo app
JavaScript
37
star
43

monad-validate

(NOTE: REPOSITORY MOVED TO NEW OWNER: https://github.com/lexi-lambda/monad-validate) A Haskell monad transformer library for data validation
Haskell
32
star
44

pod42

Python
31
star
45

gitlab-graphql

Install gitlab and expose the gitlab api's over GraphQL
JavaScript
29
star
46

codegen-assets

TypeScript
28
star
47

data-hub

Explore data sources from a native GraphQL API, database schemas to custom code contributed by the community.
PLpgSQL
27
star
48

pg-client-hs

A low level Haskell library to connect to postgres
Haskell
25
star
49

template-gallery

Repository containing schema sharing packages.
PLpgSQL
24
star
50

yelp-clone-react

A Yelp clone built using React + GraphQL + Hasura
JavaScript
24
star
51

authz-workshop

TSQL
23
star
52

ndc-hub

Shell
22
star
53

graphql-schema-stitching-demo

Schema Stitching Example with Hasura GraphQL + MetaWeather API
JavaScript
22
star
54

github-integration-starter

Try out Hasura's GitHub Integration on Cloud Projects using the examples in this repo.
22
star
55

ndc-typescript-deno

Instant Hasura Native Data Connector by writing Typescript Functions
TypeScript
22
star
56

hasura-cloud-preview-apps

TypeScript
21
star
57

issues

Dump and sync org wide issues into postgres and visualise with metabase.
Python
19
star
58

imad-app

Base repository for IMAD course application.
JavaScript
19
star
59

realm-pg-sync

The realm-pg-sync microservice
JavaScript
18
star
60

graphql-data-specification

A specification for Data APIs with GraphQL
Haskell
18
star
61

hasura-discord-docs-bot

PLpgSQL
18
star
62

react-apollo-todo

A todo app with react, apollo demonstrating graphql queries, mutations and subscriptions.
CSS
17
star
63

architect-graphql-workshop

JavaScript
16
star
64

continuous-backup

Postgres wal-e continuous backup system
Shell
16
star
65

preview-actions

Starter kit to try out actions
JavaScript
16
star
66

auth-ui-kit

Web UI Kit for Hasura Authentication
JavaScript
15
star
67

graphql-example-apps

PLpgSQL
14
star
68

js-sdk

JavaScript
14
star
69

ndc-spec

NDC Specification and Reference Implementation
Rust
14
star
70

cloud-functions-boilerplates

Boilerplates for cloud functions (AWS Lambda, Google Cloud Functions, Azure Cloud Functions, Zeit, etc.) that work in conjunction with Hasura GraphQL Engine's event triggers
JavaScript
14
star
71

graphql-subscriptions-benchmark

TypeScript
13
star
72

sample-apps

TypeScript
12
star
73

smooth-checkout-buildkite-plugin

All the things you need during a Buildkite checkout 🧈 πŸͺ
Shell
12
star
74

sqlite-dataconnector-agent

SQLite Data Connector Agent for Hasura GQL Engine. Please note that this repository is a mirror. We will still accept PRs, but will have to mirror them to our upstream repo.
TypeScript
11
star
75

github-bot

Hasura's own GitHub bot πŸ€–
JavaScript
11
star
76

generator-hasura-web

JavaScript
11
star
77

demo-apps

Config to deploy Hasura demo apps using Docker Compose
HTML
11
star
78

smooth-secrets-buildkite-plugin

A buildkite plugin to setup ssh keys and env secrets for your pipelines 🧈 πŸ”’
Shell
11
star
79

chat-app-android

Java
10
star
80

custom-resolvers-boilerplate

A boilerplate for writing custom resolvers with Hasura GraphQL Engine
JavaScript
10
star
81

open-data-domain-specification

Rust
10
star
82

android-sdk

The Android SDK for Hasura
Java
9
star
83

sample-auth-webhook

Sample auth webhooks for the Hasura GraphQL engine
JavaScript
9
star
84

generator-hasura-node

JavaScript
9
star
85

graphql-asia-workshop

JavaScript
9
star
86

reactathon-workshop

9
star
87

go-buildkite-dsl

Write Buildkite configs in Go πŸͺ πŸ“
Go
8
star
88

graphql-on-various-pg

Hasura's GraphQL engine on various Postgres systems/providers
Shell
8
star
89

cli-plugins-index

8
star
90

ndc-sdk-typescript

NDC SDK for TypeScript
TypeScript
8
star
91

graphql-weather-api

A simple GraphQL express weather api server boilerplate
JavaScript
8
star
92

supergraph-top-n-challenge

JavaScript
8
star
93

haskell-docker-builder

Package haskell binaries as docker images
Makefile
7
star
94

graphql-engine-install-manifests

Various installation manifests for Hasura's GraphQL Engine
Shell
7
star
95

laravel-todo-hge

A sample Laravel app with an auth webhook
PHP
7
star
96

awesome-react-fullstack

A review of the must know concepts & tools for going fullstack with react. Awesome list to the top tools and learning resources for each concept.
7
star
97

weaviate_gdc

POC: Weaviate data connector
TypeScript
7
star
98

ai-workshop-hasuracon23

Jupyter Notebook
6
star
99

ndc-postgres

Hasura v3 Data Connector for PostgreSQL
Rust
6
star
100

trigger-serverless-zeit-example

JavaScript
6
star