authepy.
Dev Hub / React Engine (SPA)

Headless identity for React SPAs.

Build 100% custom UI states securely in the browser. Using Authepy's Restricted Keys, you can verify emails directly from your React frontend—no backend proxy required.

Vite Ready
|
Restricted Keys
|
0 Backend Config
~ / react-spa-architecture
// 1. The React Client
~ npm create vite@latest my-app --template react
// 2. Whitelist your frontend domain in the Dashboard
✓ CORS policies enabled
VITE_AUTHEPY_KEY="rk_live_..."
01

The Restricted Key

The most critical rule of frontend development is that you cannot hide secrets in the browser. If you put a Standard Key in your React code, malicious actors will steal it.

Authepy solves this with Restricted Keys (`rk_live_...`). These keys are cryptographically bound to your specific domain names. Even if stolen, our Edge Router instantly rejects any request that doesn't originate from your whitelisted website.

Authepy Control Plane Dashboard UI
Create New Restricted Key
Allowed Domains (CORS)
https://yourdomain.com https://app.yourdomain.com http://localhost:3000

OTP requests matching from any of these Origins will be processed.

02

The Headless Component

With your Restricted Key safe to expose, you have total control over the React UI. No bulky Authepy dependencies are required. Use standard useState to manage the form transition, and use the native fetch API to talk directly to Authepy.

src/components/Login.jsx React Client
import React, { useState } from 'react';
const AUTHEPY_API = 'https://api.authepy.com/api'; 
const RESTRICTED_API_KEY = 'YOUR_RESTRICTED_KEY_HERE'; 

export default function SPALogin() {
  const [email, setEmail] = useState('');
  const [code, setCode] = useState('');
  const [requestId, setRequestId] = useState(null);
  const [status, setStatus] = useState('idle'); 

  const handleSendOTP = async (e) => {
    e.preventDefault();
    setStatus('loading');
    const response = await fetch(`${AUTHEPY_API}/otp/request`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${RESTRICTED_API_KEY}`
      },
      body: JSON.stringify({ email })
    });
    const data = await response.json();
    if (data.success) {
      setRequestId(data.requestId);
      setStatus('verify');
    }
  };

  const handleVerifyOTP = async (e) => {
    e.preventDefault();
    setStatus('loading');
    const response = await fetch(`${AUTHEPY_API}/otp/verify`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${RESTRICTED_API_KEY}`
      },
      body: JSON.stringify({ requestId, userGuess: code })
    });
    const data = await response.json();
    if (data.success) setStatus('success');
  };

  // Render Logic (Success, Verify, or Initial form)
  if (status === 'success') return 
Logged in!
; if (status === 'verify') return ( /* OTP Code Input */ ); return ( /* Email Input */ ); }
03 /

Zero Backend Required

Because Authepy's Edge Router handles the email dispatch and cryptographic verification for you, you don't need to spin up an Express proxy server just to authenticate users on a static S3 or Vercel deployment.

Auto-Fill UX Enabled

By building the form yourself, you can add autoComplete="one-time-code" to your input fields, instantly triggering native iOS/Android code suggestions from the keyboard.

Initialize your frontend.

Stop fighting with bloated frontend authentication SDKs. Generate your Restricted Keys and build a completely custom, headless UI today.