React SDK Guide

Step-by-step guide for developers using the React SDK with the useAuth hook.

Installation

npm install get401

Step 1 - Wrap your app with Get401Provider

Import and wrap your application root component with Get401Provider.

import { Get401Provider } from 'get401'
 
function App() {
  return (
    <Get401Provider
      appId="your-app-id"
      debug={true}
      onSuccess={(user) => console.log('User logged in:', user)}
      onError={(error) => console.error('Auth error:', error)}
    >
      <YourApp />
    </Get401Provider>
  )
}

Get401Provider props:

Prop Type Description
appId string Your application ID (or set via window.GET401_APP_ID)
debug boolean Enable debug logging (default: false)
onSuccess (user: User) => void Callback on successful authentication
onError (error: string) => void Callback on error

Step 2 - Use the useAuth hook

import { useState } from 'react'
import { useAuth } from 'get401'
 
function LoginPage() {
  const { login, challengeOTP, user, status, nextStep, error, isLoading } = useAuth()
  const [email, setEmail] = useState('')
  const [password, setPassword] = useState('')
  const [otpCode, setOtpCode] = useState('')
 
  // ... rest of component
}

Step 3 - Handle login

Both email and password are sent together in a single request. If MFA is enabled, the response returns next: 'otp'.

const handleLogin = async (e) => {
  e.preventDefault()
  try {
    const response = await login(email, password)
    if (response.next === 'otp') {
      // Show OTP input form
    }
  } catch (err) {
    console.error('Login failed:', err)
  }
}

Step 4 - Handle OTP verification

const handleOTP = async (e) => {
  e.preventDefault()
  try {
    await challengeOTP(otpCode)
  } catch (err) {
    console.error('OTP verification failed:', err)
  }
}

Step 5 - Check authentication status

if (status === 'authenticated') {
  return <div>Welcome {user?.email}!</div>
}

Step 6 - Show OTP form when required

if (nextStep === 'otp') {
  return (
    <form onSubmit={handleOTP}>
      <input
        type="text"
        value={otpCode}
        onChange={(e) => setOtpCode(e.target.value)}
        placeholder="Enter OTP code"
      />
      <button type="submit" disabled={isLoading}>
        Verify OTP
      </button>
      {error && <div>{error}</div>}
    </form>
  )
}

Step 7 - Login form

return (
  <form onSubmit={handleLogin}>
    <input
      type="email"
      value={email}
      onChange={(e) => setEmail(e.target.value)}
      placeholder="Email"
      required
    />
    <input
      type="password"
      value={password}
      onChange={(e) => setPassword(e.target.value)}
      placeholder="Password"
      required
    />
    <button type="submit" disabled={isLoading}>
      Login
    </button>
    {error && <div>{error}</div>}
  </form>
)

Authentication Flow

Login

  1. User submits email + password via login(email, password) - sent in one request
  2. Server responds with { next: 'otp' } if MFA is required, otherwise user is authenticated
  3. If nextStep === 'otp', call challengeOTP(code)
  4. On success, user object is available

Registration

  1. Call register(email, password)
  2. Response has setup: 'email' or setup: 'otp'
  3. If setup === 'email': call challengeEmailSetup(code) with the verification code
  4. If setup === 'otp' (or after email verification): call getOTPSetup() to get QR code, then verifyOTPSetup(code)

API Reference

useAuth hook

const {
  status,        // 'idle' | 'loading' | 'authenticated' | 'unauthenticated'
  user,          // User | null
  nextStep,      // 'email' | 'otp' | null
  error,         // string | null
  isLoading,     // boolean
  isAuthenticated, // boolean
 
  login(email, password),
  challengeOTP(code),
  logout(),
  getUser(),
  register(email, password),
  challengeEmailSetup(code),
  getOTPSetup(),
  verifyOTPSetup(code),
  refreshToken(),
  clearError(),
} = useAuth()

Get401Provider

interface Get401ProviderProps {
  appId?: string
  onSuccess?: (user: User) => void
  onError?: (error: string) => void
  debug?: boolean
  children: React.ReactNode
}

TypeScript

The package is written in TypeScript and includes full type definitions. All exports are fully typed.