This is a monorepo template for creating applications using Vite 7, HeroUI (v2) and a flexible authentication layer that supports multiple OAuth providers (Auth0, Dex, and more). Built with Turborepo and Yarn 4 workspaces for optimal developer experience and performance.
If you appreciate my work, please consider giving it a star! 🤩
Ths plugin uses our @sctg/vite-plugin-github-pages-spa Vite 6 plugin for handling the Github Pages limitations with SPA.
- 🚀 Fast development with Vite 7
- 🎨 Beautiful UI components from HeroUI v2
- 🔐 Flexible authentication with multiple OAuth providers (Auth0, Dex)
- 🌐 Internationalization with i18next (6 languages included)
- 🌙 Dark/Light mode support
- 📱 Responsive design
- 🍪 Cookie consent management
- 🧩 Type-safe with TypeScript
- 🧹 Code quality with ESLint 9
- 📦 Optimized build with manual chunk splitting
- ⚡ Turborepo for intelligent caching and parallel builds
- 🧶 Yarn 4 workspaces for efficient dependency management
- Vite 7
- HeroUI
- Tailwind CSS 4
- Tailwind Variants
- React 19
- i18next
- Auth0 React SDK
- OIDC Client TS (For Dex and other OAuth providers)
- ESLint 9
- TypeScript
- Framer Motion
- Turborepo (Monorepo build system)
- Yarn 4 (Package manager with workspaces)
# Clone the repository
git clone https://github.com/sctg-development/vite-react-heroui-auth0-template.git
# Change directory
cd vite-react-heroui-auth0-template
# Install Yarn 4 (if not already installed)
corepack enable
yarn set version 4.9.2
# Install all dependencies (uses Yarn workspaces)
yarn install
# Create a .env file with your Auth0 credentials
cat <<EOF > .env
AUTHENTICATION_PROVIDER_TYPE=auth0
AUTH0_CLIENT_ID=your-auth0-client-id
AUTH0_CLIENT_SECRET=your-auth0-client-secret
AUTH0_DOMAIN=your-auth0-domain
AUTH0_SCOPE="openid profile email read:api write:api admin:api"
AUTH0_AUDIENCE=http://localhost:5173
API_BASE_URL=http://localhost:8787/api
CORS_ORIGIN=http://localhost:5173
READ_PERMISSION=read:api
WRITE_PERMISSION=write:api
ADMIN_PERMISSION=admin:api
AUTHENTICATION_PROVIDER_TYPE=auth0
EOF
# Start both applications with environment variables
yarn dev:envFor more detailed commands, see the Turborepo Guide.
- Vite, OAuth & HeroUI Template
- Star the project
- Live demo
- On Github Pages ?
- Features
- Technologies Used
- Quick Start
- Table of Contents
- Authentication
- Internationalization
- Cookie Consent
- Project Structure
- Available Scripts in the frontend application
- Deployment
- Tailwind CSS 4
- How to Use
- Contributing
- License
- Authentication Architecture
This template provides a flexible authentication system with support for multiple OAuth providers. The architecture uses an abstraction layer that allows you to easily switch between different providers while maintaining a consistent API. Currently, the template supports:
- Auth0 (Default) - Using the Auth0 React SDK
- Dex - Using the OIDC Client TS library
The authentication system can be extended to support other OAuth providers like Azure AD, Okta, or any OAuth 2.0 compliant service by implementing the provider interface.
-
Create an Auth0 Account:
- Go to Auth0 and sign up for a free account.
-
Create a New Application:
- In the Auth0 dashboard, navigate to the "Applications" section.
- Click on "Create Application".
- Choose a name for your application.
- Select "Single Page Web Applications" as the application type.
- Click "Create".
-
Configure Application Settings:
- In the application settings, you will find your
Client IDandDomain. - Set the "Allowed Callback URLs" to
http://localhost:5173(or your development URL). - Set the "Allowed Logout URLs" to
http://localhost:5173(or your development URL). - Set the "Allowed Web Origins" to
http://localhost:5173(or your development URL).
- In the application settings, you will find your
-
Sample settings:
- The settings used by the demo deployment on GitHub Pages are:
- Allowed Callback URLs:
https://sctg-development.github.io/vite-react-heroui-auth0-template - Allowed Logout URLs:
https://sctg-development.github.io/vite-react-heroui-auth0-template - Allowed Web Origins:
https://sctg-development.github.io - On Github repository settings, the
AUTH0_CLIENT_IDsecret is set to the Auth0 client ID and theAUTH0_DOMAINsecret is set to the Auth0 domain. - The full Auth0 configuration screenshot is available here.
- Allowed Callback URLs:
- The settings used by the demo deployment on GitHub Pages are:
To keep your Auth0 credentials secure, use environment variables. Create a .env file in the root of your project and add the following:
AUTH0_CLIENT_ID=your-auth0-client-id
AUTH0_CLIENT_SECRET=your-auth0-secret
AUTH0_DOMAIN=your-auth0-domain
AUTH0_SCOPE="openid profile email read:api write:api"
AUTH0_AUDIENCE=https://myapi.example.com
API_BASE_URL=https://myapi.example.com/api
CORS_ORIGIN=https://your-github-username.github.io
READ_PERMISSION=read:api
WRITE_PERMISSION=write:api
ADMIN_PERMISSION=admin:api
AUTHENTICATION_PROVIDER_TYPE=auth0For using the provided GitHub Actions workflows, you need to add the following secrets to your repository:
AUTH0_CLIENT_ID=your-auth0-client-id
AUTH0_CLIENT_SECRET=your-auth0-secret
AUTH0_DOMAIN=your-auth0-domain
AUTH0_SCOPE="openid profile email read:api write:api"
AUTH0_AUDIENCE=https://myapi.example.com
API_BASE_URL=https://myapi.example.com/api
CORS_ORIGIN=https://your-github-username.github.io
READ_PERMISSION=read:api
WRITE_PERMISSION=write:api
ADMIN_PERMISSION=admin:api
AUTHENTICATION_PROVIDER_TYPE=auth0each secrets should be manually entered in Github like:

You can use the AuthenticationGuard component to protect routes that require authentication. This component works with any configured provider and will redirect users to the login page if they are not authenticated.
import { AuthenticationGuard } from "./authentication";
<Route element={<AuthenticationGuard component={DocsPage} />} path="/docs" />;The template includes a fully-configured secure API call system that demonstrates how to communicate with protected backend services using Auth0 token authentication.
To enable secure API calls in your application:
-
Create an API in Auth0 Dashboard:
- Navigate to "APIs" section in the Auth0 dashboard
- Click "Create API"
- Provide a descriptive name (e.g., "My Application API")
- Set the identifier (audience) - typically a URL or URI (e.g.,
https://api.myapp.com) - Configure the signing algorithm (RS256 recommended)
-
Configure API Settings:
- Enable RBAC (Role-Based Access Control) if you need granular permission management
- Define permissions (scopes) that represent specific actions (e.g.,
read:api,write:api) - Configure token settings as needed (expiration, etc.)
- Include permissions in the access token
-
Set Environment Variables: Add the following to your
.envfile:AUTH0_AUDIENCE=your-api-identifier AUTH0_SCOPE="openid profile email read:api write:api" API_BASE_URL=http://your-api-url.com
-
Sample Configuration: For reference, view the Auth0 API configuration used in the demo deployment.
The template provides a hook useSecuredApi that handles token acquisition and authenticated requests for any configured provider:
import { useSecuredApi } from "@/authentication";
// Inside your component:
const { getJson, postJson, deleteJson } = useSecuredApi();
// GET request to a secured API endpoint
const apiData = await getJson(`${import.meta.env.API_BASE_URL}/endpoint`);
// POST request to a secured API endpoint
const apiData = await postJson(`${import.meta.env.API_BASE_URL}/endpoint`, {
data: "example",
});
// DELETE request to a secured API endpoint
const apiData = await deleteJson(`${import.meta.env.API_BASE_URL}/endpoint`);This function automatically:
- Requests the appropriate token with configured audience and scope
- Attaches the token to the request header
- Handles errors appropriately
- Returns the JSON response
For more control, you can use the authentication provider API directly:
import { useAuth } from "@/authentication";
// Inside your component:
const auth = useAuth();
// Access authentication state
const isLoggedIn = auth.isAuthenticated;
const userData = auth.user;
// Perform authentication actions
await auth.login();
await auth.logout();
// Get tokens for API calls
const token = await auth.getAccessToken();
// Make API calls
const data = await auth.getJson(`${import.meta.env.API_BASE_URL}/endpoint`);
await auth.postJson(`${import.meta.env.API_BASE_URL}/endpoint`, {
key: "value",
});This function automatically:
- Requests the appropriate token with configured audience and scope
- Attaches the token to the request header
- Handles errors appropriately
- Returns the JSON response
You can check user permissions with any configured authentication provider:
import { useAuth } from "@/authentication";
// Inside your component:
const auth = useAuth();
const canReadData = await auth.hasPermission("read:api");
// Or using the useSecuredApi hook
import { useSecuredApi } from "@/authentication";
const { hasPermission } = useSecuredApi();
const canReadData = await hasPermission("read:api");The permission system works across different providers, with each implementation handling the specific token format of that provider.
This template includes a AuthenticationGuardWithPermission component that works with any configured provider and wraps a component to check if the user has the required permission:
import { AuthenticationGuardWithPermission } from "@/authentication";
<AuthenticationGuardWithPermission permission="read:api">
<ProtectedComponent />
</AuthenticationGuardWithPermission>;For demonstration purposes, the template includes a Cloudflare Worker that acts as a secured backend API:
- Start the Worker with environment variables:
# From the root directory
yarn dev:worker:env- Test API Integration:
With both your application and the worker running, navigate to the
/apiroute in your application to see the secure API call in action.
- Your application requests an access token from Auth0 with specific audience and scope
- Auth0 issues a JWT token containing the requested permissions
- Your application includes this token in the Authorization header
- The backend API validates the token using Auth0's public key
- If valid, the API processes the request according to the permissions in the token
This template uses i18next for internationalization. The configuration and available languages are defined in the src/i18n.ts file.
To add a new language to the application, follow these steps:
-
Update the
availableLanguagesarray:- Open the
src/i18n.tsfile. - Add a new object to the
availableLanguagesarray with the following properties:code: The ISO 639-1 language code (e.g., "en-US").nativeName: The native name of the language (e.g., "English").isRTL: Whether the language is right-to-left (e.g.,false).
- Open the
-
Create a Translation File:
- In the
src/locales/basedirectory, create a new JSON file named with the language code (e.g.,en-US.json). - Add the translations for the new language in this file.
- In the
-
Update the Load Path:
- In the
src/i18n.tsfile, manually add a switch case to theloadPathfunction to handle the new JSON file for the added language.
- In the
The LanguageSwitch component allows users to switch between the available languages. It is defined in the src/components/language-switch.tsx file.
- The component uses the i18n instance to change the language and update the document metadata.
- It automatically updates the document direction based on the language (left-to-right or right-to-left).
- The selected language is stored in
localStorageto persist the user's preference.
To use the LanguageSwitch component in your application, simply include it in your JSX:
<LanguageSwitch
availableLanguages={[
{ code: "en-US", nativeName: "English", isRTL: false, isDefault: true },
{ code: "fr-FR", nativeName: "Français", isRTL: false },
]}
/>or more simply using the availableLanguages array defined in the src/i18n.ts file:
import { availableLanguages } from "@/i18n";
<LanguageSwitch availableLanguages={availableLanguages} />;This component will render a dropdown menu with the available languages, allowing users to switch languages easily.
The default configuration uses the i18next-http-backend plugin for language lazy loading. This means that translations are loaded only when needed, improving the application's performance.
- Configuration:
src/i18n.ts - Translations:
src/locales/base - Language Switch:
src/components/language-switch.tsx
By following the steps above, you can easily add new languages and manage internationalization for your application.
This template includes a cookie consent management system to comply with privacy regulations like GDPR. The system displays a modal dialog asking users for consent to use cookies and stores their preference in the browser's localStorage.

- Modern modal-based UI with blur backdrop
- Internationalized content for all supported languages
- Stores user preferences in localStorage
- Provides a context API for checking consent status throughout the application
- Supports both accepting and rejecting cookies
The cookie consent feature can be enabled or disabled through the site configuration:
- Enable/Disable Cookie Consent:
- Open the
src/config/site.tsfile - Set the
needCookieConsentproperty totrueorfalse:
- Open the
export const siteConfig = () => ({
needCookieConsent: true, // Set to false if you don't need cookie consent
// ...other configuration
});- Context Provider:
src/contexts/cookie-consent-context.tsx- Provides a React context to manage consent state - UI Component:
src/components/cookie-consent.tsx- Renders the consent modal using HeroUI components - Consent Status: The consent status can be one of three values:
pending: Initial state, user hasn't made a decision yetaccepted: User has accepted cookiesrejected: User has rejected cookies
You can access the cookie consent status in any component using the useCookieConsent hook:
import { useCookieConsent } from "@/contexts/cookie-consent-context";
const MyComponent = () => {
const { cookieConsent, acceptCookies, rejectCookies, resetCookieConsent } =
useCookieConsent();
// Load analytics only if cookies are accepted
useEffect(() => {
if (cookieConsent === "accepted") {
// Initialize analytics, tracking scripts, etc.
}
}, [cookieConsent]);
// ...rest of your component
};- Modify the appearance of the consent modal in
src/components/cookie-consent.tsx - Add custom tracking or cookie management logic in the
acceptCookiesandrejectCookiesfunctions insrc/contexts/cookie-consent-context.tsx - Update the cookie policy text in the language files (e.g.,
src/locales/base/en-US.json)
This template follows a monorepo structure managed by Turborepo with Yarn 4 workspaces, containing the frontend application and Cloudflare Worker.
vite-react-heroui-auth0-template/
├── package.json # Root package.json with Turborepo + workspaces
├── turbo.json # Turborepo configuration
├── .yarnrc.yml # Yarn 4 configuration
├── yarn.lock # Unified lockfile for all packages
├── TURBOREPO-GUIDE.md # Turborepo usage guide
├── apps/
│ ├── client/ # Frontend application
│ │ ├── public/ # Static assets
│ │ ├── src/
│ │ │ ├── authentication/ # Authentication system
│ │ │ │ ├── auth-components.tsx # Authentication UI components
│ │ │ │ ├── auth-root.tsx # Root authentication provider
│ │ │ │ ├── index.ts # Exports
│ │ │ │ └── providers/ # Provider implementations
│ │ │ │ ├── auth-provider.ts # Provider interface
│ │ │ │ ├── auth0-provider.tsx # Auth0 implementation
│ │ │ │ ├── dex-provider.tsx # Dex implementation
│ │ │ │ └── use-auth.tsx # Auth context and hooks
│ │ │ ├── components/ # Reusable UI components
│ │ │ ├── config/ # Configuration files
│ │ │ ├── hooks/ # Custom React hooks
│ │ │ ├── layouts/ # Page layout components
│ │ │ ├── locales/ # Translation files
│ │ │ ├── pages/ # Page components
│ │ │ ├── styles/ # Global styles
│ │ │ ├── types/ # TypeScript definitions
│ │ │ ├── App.tsx # Main application component
│ │ │ ├── i18n.ts # i18next configuration
│ │ │ ├── main.tsx # Application entry point
│ │ │ └── provider.tsx # HeroUI provider setup
│ │ ├── tailwind.config.js # Tailwind CSS configuration
│ │ ├── vite.config.ts # Vite configuration
│ │ └── update-heroui.ts # Helper script to update HeroUI packages
│ └── cloudflare-worker/ # Cloudflare Worker for testing API
│ ├── src/
│ ├── wrangler.jsonc # Cloudflare Worker configuration
│ └── package.json # Worker dependencies
├── .github/ # GitHub workflows and configuration
├── .vscode/ # VS Code configuration
└── template.code-workspace # VS Code workspace configuration
This monorepo uses Turborepo for task orchestration. All scripts can be run from the root directory:
# Start all applications in development mode
yarn dev
# Start all applications with environment variables
yarn dev:env
# Start only the client application
yarn dev:client
# Start only the client application with environment variables
yarn dev:client:env
# Start only the Cloudflare Worker
yarn dev:worker
# Start only the Cloudflare Worker with environment variables
yarn dev:worker:env# Build all applications
yarn build
# Build all applications with environment variables
yarn build:env
# Build only the client application
yarn build:client
# Build only the client with environment variables
yarn build:client:env
# Build only the Cloudflare Worker
yarn build:worker
# Build only the Cloudflare Worker with environment variables
yarn build:worker:env# Run ESLint on all packages
yarn lint
# Run type checking on all packages
yarn type-check
# Run tests on all packages
yarn test
# Clean all build artifacts and caches
yarn clean
# Deploy the Cloudflare Worker
yarn deploy:worker
# Update HeroUI packages (run from client directory)
cd apps/client && yarn update:herouiFor more detailed information, see the Turborepo Guide.
This template includes a GitHub Actions workflow to automatically deploy your application to GitHub Pages. To use this feature:
- Enable GitHub Pages in the repository settings and set the source to GitHub Actions
- Enable GitHub Actions in the repository settings
- Add your Auth0 credentials as GitHub repository secrets:
AUTH0_CLIENT_IDAUTH0_DOMAIN
- Push the changes to your repository
- The application will be deployed automatically on each push to the main branch
This template uses Tailwind CSS 4, which is a utility-first CSS framework. You can customize the styles by modifying the tailwind.config.js file.
HeroUI supports Tailwind CSS 4 out of the box starting from version 2.8.
To clone the project, run the following command:
git clone https://github.com/sctg-development/vite-react-heroui-auth0-template.gitThis project uses Yarn 4 with workspaces. Install all dependencies from the root:
# Enable Yarn 4 if not already done
corepack enable
yarn set version 4.9.2
# Install all dependencies
yarn install# Start all applications with environment variables
yarn dev:env
# Or start individual applications
yarn dev:client:env # Client only
yarn dev:worker:env # Cloudflare Worker onlyThis template uses Turborepo which provides:
- Intelligent caching: Build outputs are cached and shared across team members
- Parallel execution: Tasks run in parallel when possible
- Dependency awareness: Tasks run in the correct order based on dependencies
- Incremental builds: Only rebuild what changed
- Remote caching: Share build caches across your team (optional)
If you're migrating from the previous npm-based setup, here's the command mapping:
| Old npm command | New Yarn command |
|---|---|
cd client && npm run dev:env |
yarn dev:client:env |
cd cloudflare-fake-secured-api && npm run dev:env |
yarn dev:worker:env |
cd client && npm run build:env |
yarn build:client:env |
cd cloudflare-fake-secured-api && npm run build:env |
yarn build:worker:env |
cd client && npm run lint |
yarn lint (runs on all packages) |
In the apps/client/vite.config.ts file, all @heroui packages are manually split into a separate chunk. This is done to reduce the size of the main bundle. You can remove this configuration if you don't want to split the packages.
Contributions are welcome! Please feel free to submit a Pull Request.
This template is primarily licensed under the MIT license.
Exception: Four specific files (site-loading.tsx, language-switch.tsx, vite.config.ts, and auth0.tsx) are licensed under the AGPL-3.0 license as they contain code originating from my other repositories.
The authentication system uses a provider-based architecture that allows you to easily switch between different OAuth providers:
All authentication providers implement a common interface that defines standard authentication methods:
export interface AuthProvider {
// Authentication state
isAuthenticated: boolean;
isLoading: boolean;
user: AuthUser | null;
// Core authentication methods
login(options?: LoginOptions): Promise<void>;
logout(options?: LogoutOptions): Promise<void>;
getAccessToken(options?: TokenOptions): Promise<string | null>;
// Permission handling
hasPermission(permission: string): Promise<boolean>;
// API interaction helpers
getJson(url: string): Promise<any>;
postJson(url: string, data: any): Promise<any>;
deleteJson(url: string): Promise<any>;
}To use the authentication system in your application, wrap your components with the AuthenticationProvider:
import { AuthenticationProvider } from "./authentication";
// For Auth0 (default)
<AuthenticationProvider providerType="auth0">
<App />
</AuthenticationProvider>
// For Dex
<AuthenticationProvider
providerType="dex"
>
<App />
</AuthenticationProvider>To use Auth0, follow these steps:
-
Create an Auth0 Account:
- Go to Auth0 and sign up for a free account.
-
Create a New Application:
- In the Auth0 dashboard, navigate to the "Applications" section.
- Click on "Create Application".
- Choose a name for your application.
- Select "Single Page Web Applications" as the application type.
- Click "Create".
-
Configure Application Settings:
- In the application settings, you will find your
Client IDandDomain. - Set the "Allowed Callback URLs" to
http://localhost:5173(or your development URL). - Set the "Allowed Logout URLs" to
http://localhost:5173(or your development URL). - Set the "Allowed Web Origins" to
http://localhost:5173(or your development URL).
- In the application settings, you will find your
-
Sample settings:
- The settings used by the demo deployment on GitHub Pages are:
- Allowed Callback URLs:
https://sctg-development.github.io/vite-react-heroui-auth0-template - Allowed Logout URLs:
https://sctg-development.github.io/vite-react-heroui-auth0-template - Allowed Web Origins:
https://sctg-development.github.io - On Github repository settings, the
AUTH0_CLIENT_IDsecret is set to the Auth0 client ID and theAUTH0_DOMAINsecret is set to the Auth0 domain. - The full Auth0 configuration screenshot is available here.
- Allowed Callback URLs:
- The settings used by the demo deployment on GitHub Pages are:
-
Configure API in Auth0:
- Navigate to "APIs" section in the Auth0 dashboard
- Click "Create API"
- Provide a descriptive name (e.g., "My Application API")
- Set the identifier (audience) - typically a URL or URI (e.g.,
https://api.myapp.com) - Configure the signing algorithm (RS256 recommended)
-
Configure API Settings:
- Enable RBAC (Role-Based Access Control) if you need granular permission management
- Define permissions (scopes) that represent specific actions (e.g.,
read:api,write:api) - Configure token settings as needed (expiration, etc.)
- Include permissions in the access token
-
Set Environment Variables: Add the following to your
.envfile:AUTHENTICATION_PROVIDER_TYPE=auth0 AUTH0_AUDIENCE=your-api-identifier AUTH0_SCOPE="openid profile email read:api write:api" API_BASE_URL=http://your-api-url.com
-
Sample Configuration: For reference, view the Auth0 API configuration used in the demo deployment.
Dex is an identity service that uses OpenID Connect to drive authentication for other apps. To use Dex as your authentication provider:
-
Setup a Dex Server:
- Install and configure a Dex server following the official documentation
- Configure Dex to support the OAuth 2.0 authorization code flow
-
Register your Application in Dex:
- Add your application to the Dex configuration
- Set the redirect URI to your application's callback URL (e.g.,
http://localhost:5173)
-
Configure the Dex Provider:
- Create a
.envfile with your Dex configuration:
AUTHENTICATION_PROVIDER_TYPE=dex DEX_AUTHORITY=https://your-dex-server.com DEX_CLIENT_ID=your-dex-client-id DEX_SCOPE="openid profile email" DEX_AUDIENCE=https://your-api.com DEX_JWKS_ENDPOINT=https://your-dex-server.com/dex/keys
- Create a
-
Initialize the Dex Provider:
import { AuthenticationProvider } from "./authentication"; <AuthenticationProvider providerType="dex"> <App /> </AuthenticationProvider>;
To add support for additional OAuth providers:
- Create a new provider implementation file in
src/authentication/providers/ - Implement the
AuthProviderinterface - Add the new provider to the
AuthProviderWrapperinsrc/authentication/providers/use-auth.tsx - Add configuration in
src/authentication/auth-root.tsx
The modular design makes it easy to extend the authentication system with new providers while maintaining a consistent API throughout your application.
