From 559f48a6ce018a95d61ab9aef18fac555e67e6ea Mon Sep 17 00:00:00 2001 From: Julien Lavocat Date: Thu, 15 Jan 2026 15:53:19 +0100 Subject: [PATCH] docs: Add Auth0 tutorial --- .../00500-authentication/00200-Auth0.md | 267 ++++++++++++++++++ docs/src/css/custom.css | 5 +- 2 files changed, 271 insertions(+), 1 deletion(-) create mode 100644 docs/docs/00200-core-concepts/00500-authentication/00200-Auth0.md diff --git a/docs/docs/00200-core-concepts/00500-authentication/00200-Auth0.md b/docs/docs/00200-core-concepts/00500-authentication/00200-Auth0.md new file mode 100644 index 00000000000..81737fb1ac4 --- /dev/null +++ b/docs/docs/00200-core-concepts/00500-authentication/00200-Auth0.md @@ -0,0 +1,267 @@ +--- +title: Auth0 +--- + +import { StepByStep, Step, StepText, StepCode } from "@site/src/components/Steps"; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +This guilde will walk you through integrating Auth0 authentication with your SpacetimeDB application. + +## Prerequisites + +We assume you have the following prerequisites in place: + +- A working SpacetimeDB project, follow our [React Quickstart Guide](../../00100-intro/00200-quickstarts/00100-react.md) if you need help setting this up. + +## Getting started + + + + + Install the Auth0 React SDK into your React application. + + + + +```bash +npm add @auth0/auth0-react +``` + + +```bash +yarn add @auth0/auth0-react +``` + + +```bash +pnpm add @auth0/auth0-react +``` + + +```bash +bun add @auth0/auth0-react +``` + + + + + + + +1. Head to the [Auth0 Dashboard](https://manage.auth0.com/dashboard/) +2. Click on **Applications** > **Applications** > **Create Application** +3. In the popup, enter a name for your app, select `Single Page Web Application` + as the app type and click Create +4. Switch to the **Settings** tab on the **Application Details** page +5. Save the Domain and Client ID values from the dashboard somewhere handy, you'll + need them later +6. Finally, on the Settings tab of your Application Details page, configure the + URLs from the table on the right + + + + + +| URL Type | URL | +| --------------------- | ----------------------- | +| Allowed Callback URLs | `http://localhost:5173` | +| Allowed Logout URLs | `http://localhost:5173` | +| Allowed Web Origins | `http://localhost:5173` | + + + + + + + +Create an `AutoLogin` component that automatically handles user login and ID token +retrieval using the Auth0 React SDK. This component will redirect unauthenticated +users to the Auth0 login page and provide the ID token to its children via context. + + + +```tsx +import { useAuth0 } from '@auth0/auth0-react'; +import { createContext, useContext, useEffect, useMemo, useState } from 'react'; + +const IdTokenContext = createContext(undefined); + +export function useIdToken() { + const ctx = useContext(IdTokenContext); + if (!ctx) { + throw new Error('useIdToken must be used within an IdTokenProvider'); + } + return ctx; +} + +export function AutoLogin({ children }: { children: React.ReactNode }) { + const { isLoading, isAuthenticated, loginWithRedirect, getIdTokenClaims } = + useAuth0(); + + const [idToken, setIdToken] = useState(null); + const [error, setError] = useState(null); + + useEffect(() => { + if (!isLoading && !isAuthenticated) { + loginWithRedirect().catch(err => setError(err)); + } + }, [isLoading, isAuthenticated, loginWithRedirect]); + + useEffect(() => { + let cancelled = false; + + const run = async () => { + if (isLoading) return; + + // IMPORTANT: If not authenticated, ensure token is cleared + if (!isAuthenticated) { + if (!cancelled) setIdToken(null); + return; + } + + try { + const claims = await getIdTokenClaims(); + const token = claims?.__raw ?? null; + + if (!token) { + throw new Error('Auth0 returned no ID token (__raw missing).'); + } + + if (!cancelled) { + setIdToken(token); + } + } catch (e) { + if (!cancelled) setError(e as Error); + } + }; + + run(); + return () => { + cancelled = true; + }; + }, [isLoading, isAuthenticated, getIdTokenClaims]); + + const value = useMemo(() => { + return idToken ?? undefined; + }, [idToken]); + + const ready = !isLoading && isAuthenticated && !!idToken && !error; + + if (error) { + return ( +
+

Authentication error

+
{error.message}
+
+ ); + } + + if (!ready) { + return

Loading...

; + } + + return ( + {children} + ); +} +``` + +
+
+ + + +Wrap your application with the `Auth0Provider` component to `main.tsx` to enable +authentication. + +:::info +Don't forget to remove any existing `SpacetimeDBProvider` wrapper from this +file as we will be adding it somewhere else later in this guide. +::: + + + +```tsx +import { Auth0Provider } from '@auth0/auth0-react'; +import { StrictMode } from 'react'; +import { createRoot } from 'react-dom/client'; +import App from './App.tsx'; +import { AutoLogin } from './AutoLogin.tsx'; + +createRoot(document.getElementById('root')!).render( + + + + + + + +); +``` + + + + + +Update your `App.tsx` file to use the `useIdToken` hook from the `AutoLogin` +component to get the ID token and pass it to the `DbConnection` builder. + + + +```tsx +import { useMemo } from 'react'; +import { Identity } from 'spacetimedb'; +import { SpacetimeDBProvider } from 'spacetimedb/react'; +import { useIdToken } from './AutoLogin'; +import { DbConnection, ErrorContext } from './module_bindings'; + +const onConnect = (_conn: DbConnection, identity: Identity) => { + console.log( + 'Connected to SpacetimeDB with identity:', + identity.toHexString() + ); +}; + +const onDisconnect = () => { + console.log('Disconnected from SpacetimeDB'); +}; + +const onConnectError = (_ctx: ErrorContext, err: Error) => { + console.log('Error connecting to SpacetimeDB:', err); +}; + +export default function App() { + const idToken = useIdToken(); + + const connectionBuilder = useMemo(() => { + return DbConnection.builder() + .withUri('') + .withModuleName('') + .withToken(idToken) + .onConnect(onConnect) + .onDisconnect(onDisconnect) + .onConnectError(onConnectError); + }, [idToken]); + + return ( + +
+

SpacetimeDB React App

+

You can now use SpacetimeDB in your app!

+
+
+ ); +} +``` + +
+
+ +
diff --git a/docs/src/css/custom.css b/docs/src/css/custom.css index 81afdbbbc6d..5cebb854662 100644 --- a/docs/src/css/custom.css +++ b/docs/src/css/custom.css @@ -99,6 +99,9 @@ --ifm-tabs-padding-vertical: 8px; --ifm-navbar-height: 57px; + + --ifm-footer-padding-vertical: 0; + --ifm-footer-padding-horizontal: 0; } :root .alert--info { @@ -747,4 +750,4 @@ a.card { .step-code { margin-top: 16px; } -} \ No newline at end of file +}