@teku/react-auth

Teku's react authentication

Usage no npm install needed!

<script type="module">
  import tekuReactAuth from 'https://cdn.skypack.dev/@teku/react-auth';
</script>

README

@teku/react-auth

@teku/react-auth version @teku/react-auth downloads per months Code style

Simple solution to make your React web application authentication / authorization. Designed to work with Auth0, Firebase v8 and Firebase v9. Supports Preact too.

Table of contents

Installation

npm install --dev @teku/react-auth

Concept

There are 3 supported auth drivers:

  • Auth0: Using auth0, or even in combination with Firebase Auth
  • FirebaseAuth: Using Google Firebase Auth
  • FireseProfile: Fetching user profile from Google [Firestore][service-firestore]

After initialization, these drivers will automatically handle authentication / authorization logic for you, the resolved profiles will be pushed into AuthContext through their driver ids and even trigger event handlers for us.

How To Use

Handle auth with AuthProvider

We provide AuthProvider for wrapping your components / pages, which will automatically handle authentication process for you.

import { AuthProvider } from '@teku/react-auth'

<AuthProvider {...options}>
  {children}
</AuthProvider>

There are 2 types of options:

All of options are optional, but as least 1 driver options should be provided. Option syntaxes / signatures are described using Typescript style or detailed tables in following sections.

Callbacks

onUserChanged

(driver: AuthDrivers, user: any | null) => void

This callback is fired everytime auth data changed, when the users are logged in, or logged out (null).

The driver param are driver id (like auth0, firebase...) that has auth data updated.

onError

(driver: AuthDrivers, err: Error) => void

This callback is only fired when error happens.

Driver options

The driver options (objects) will be used to initialize authentication clients.

withAuth0

These are only options which is required or provided with default values. More auth0 options can be found at Auth0 options

Option Type Description Default
domain string required Domain registed with Auth0 more info
clientId string required Auth0 client id more info
loginRedirectUri string required Callback URL after Auth0 authentication more info
logoutRedirectUri string required Callback URL after Auth0 SSO logout more info
responseType string Response type token id_token
scope string Scope openid profile email
useRefreshTokens boolean Should we use Auth0's refresh token rotation true
ssoCheckInterval integer Delay to call for rechecking SSO status, in seconds. If not set, sso checks will be triggered based on token's expire time (timer only start on page load)

Authenticated Auth0 profile contains these fields:

  • _token: auth token
  • _tokenExpiresAt: token expiration timestamp
  • uid: user id / sub
  • email: user email
  • emailVerified: where the user email has been verified
  • name: user name
  • picture: URL to user picture

withFirebaseAuth

These are options of Firebase auth driver:

Option Type Description Default
auth [Auth][#firebase-auth] required Firebase auth instance
onAuthStateChanged (user: any or null) => void required Callback whenever firebase auth user logged in / logged out (null)
customClaimMap any Map fields from custom claims into solved user {}
customTokenMap any Provide fields to be used during custom token exchanges when you combine firebase with auth0 more info { inputName: 't', outputName: 'ct' }
getCustomToken (token: string) => Promise<string> Only required when you combine firebase with auth0, async function to resolve with custom token more info
boundToAuth0 boolean Whether should firebase combine with auth0 true

Authenticated FirebaseAuth profile contains these fields:

  • _token: auth token
  • uid: user's uid
  • email: user email
  • emailVerified: where the user email has been verified
  • phoneNumber: user associated phone number
  • name: user name
  • custom claim fields
  • picture: URL to user picture

Apart from _token, uid and picture, other fields are standardized to be used as Firebase security rules more info.

withFirebaseProfile

This driver requires withFirebaseAuth to be setup, it will watch for firebase auth data changed to determine when to fetch necessary profile, to login and logout.

Option Type Description Default
getQuery (conditions: any) => Query required A function to return a Firestore Query for filter user profile, since we only take first found document, a query with limit(1) is recommended
getSnapshot (query: Query, onChange: Function, onError: Function) => Unsubscribe required A function to start watching profiles query snapshot. Usually we will need to bind onChange and onError to snapshot creator. For example query.onSnapshot(onChange, onError)
userIdField string User id field for adding into conditions uid
criteria any Additional criteria to filter profile data with firebase user id

Access auth data with AuthContext

We profile a React hook to listen for auth data context changes

import { useAuth } from '@teku/react-auth`

const auth = useAuth()

The auth context value presents authentication state of all available drivers:

{[key in AuthDrivers]}: any}

Render based on authentication status

We provide a handy AuthGate ultility component for toggling display based on authentication state. In this example, FallbackComponent is displayed if user isn't authenticated yet:

import { AuthGate } from '@teku/react-auth`

<AuthGate FallbackComponent={() => 'Please login'}>
{/* something to hide if user not authenticated */}
</AuthGate>

If you want to show something else instead of FallbackComponent while the application is determining if user is authenticated or not (due to async flow), the MaskComponent option can be used as a placeholder during this process:

import { AuthGate } from '@teku/react-auth`

<AuthGate
  FallbackComponent={() => 'Please login'}
  MaskComponent={() => 'Verifying your authentication ...'}
>
{/* something to hide if user not authenticated */}
</AuthGate>

List of available driver ids

The full list of supported driver ids can be found in AuthDrivers enum. You can use them to determine with part of auth data is being initalized

enum AuthDrivers {
  AUTH0 = 'auth0',
  FIREBASE_AUTH = 'firebase',
  FIREBASE_PROFILE = 'profile'
}

Advanced usage

Using Auth0 with Firebase

For combine Auth0 with Firebase, we need to setup a cloud function for using Firebase Admin SDK to create custom tokens.

Here is an example of getCustomToken function:

const getCustomToken = async token => {
  const exchangeToken = firebase.functions().httpsCallable('auth')
  const { data } = exchangeToken({ t: token })

  return data.token
}

After auth0 done authenticated a user, if the user's email has been verified, react-auth will try to authenticate the user through custom tokens, hence allow the user to access firebase resources.

Use with Preact

We also provide a Preact compat build. Switching between React and Preact builds is really simple, using webpack resolve.alias option:

resolve: {
  alias: {
    '@teku/react-auth': '@teku/react-auth/preact'
  }
}

SSO on Safari

Recently, we moved to Auth0 SPA SDK for better security and browser compatibility with Refresh Token Rotation. This partly avoid the third party cookies, with is considered bad for browsers' future privacy policy.

Safari is more strict on that road, providing with their adaption of Intelligent Tracking Prevention (ITP), will prevents SSO functions from working properly (see).

To fix this, we need to add specific option to auth0 driver to enable localstorage for storing auth0 tokens (not the best but the only option left):

withAuth0 = {
  ...
  cacheLocation: 'localstorage'
}

Contribution

All contributions are welcome. Feel free to open PR or share your ideas of improvement.

Thank you.