Skip to content

This guide covers in-app SDK auth components. For the simplest setup using Bridge’s hosted login page, see the Hosted auth quickstart.

Get up and running with The Bridge React plugin using in-app SDK auth components, with no redirects to external login pages.

npm i @nebulr-group/bridge-react

Put your app id in .env. For a stage or local app, add its API address too; a production app needs only the first line.

VITE_BRIDGE_APP_ID=your-app-id-here
# VITE_BRIDGE_API_BASE_URL=https://api-stage.thebridge.dev

Wrap your app in <BridgeProvider> at the root. loginRoute is the switch to in-app sign-in: with it, Bridge sends signed-out visitors to your own login page instead of its hosted one. Import the plugin’s stylesheet here too so the auth forms render styled.

// src/main.tsx
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom';
import { BridgeProvider } from '@nebulr-group/bridge-react';
import '@nebulr-group/bridge-react/styles';
import App from './App';

createRoot(document.getElementById('root')!).render(
  <StrictMode>
    <BridgeProvider config={{ loginRoute: '/auth/login' }}>
      <BrowserRouter>
        <App />
      </BrowserRouter>
    </BridgeProvider>
  </StrictMode>,
);

Key points:

  • <BridgeProvider> reads VITE_BRIDGE_* itself (REACT_APP_BRIDGE_* under Create React App). Anything you pass in config wins over the environment.
  • <BridgeProvider> sits above the router: it mounts the Bridge runtime once for the whole app.
  • Client-side rendering: Bridge requires client-side rendering; a standard Vite + React SPA needs no extra configuration.

3. Every sign-in page from one route (src/App.tsx)

Section titled “3. Every sign-in page from one route (src/App.tsx)”

<BridgeAuthRoutes> serves login, signup, the OAuth callback, set password (where verification and password-reset emails land), forgot password, magic link, passkey setup and workspace selection. Mount it once under /auth/*, and guard the routes that need a signed-in user with <ProtectedRoute>:

// src/App.tsx
import { ProtectedRoute } from '@nebulr-group/bridge-react';
import { BridgeAuthRoutes } from '@nebulr-group/bridge-react/react-router';
import { Routes, Route } from 'react-router-dom';

function App() {
  return (
    <Routes>
      {/* Public routes */}
      <Route path="/" element={<HomePage />} />
      <Route path="/auth/*" element={<BridgeAuthRoutes />} />

      {/* Requires a signed-in user */}
      <Route path="/dashboard" element={<ProtectedRoute><DashboardPage /></ProtectedRoute>} />
    </Routes>
  );
}

export default App;

<ProtectedRoute> sends a signed-out visitor to /auth/login and remembers where they were going; after sign-in they land back there.

With TanStack Router, import the same component from @nebulr-group/bridge-react/tanstack-router and mount it on a splat route:

import { BridgeAuthRoutes } from '@nebulr-group/bridge-react/tanstack-router';

const authRoute = createRoute({ getParentRoute: () => rootRoute, path: 'auth/$', component: BridgeAuthRoutes });

Without a router, render <BridgeAuthRoutes base="/auth" /> from @nebulr-group/bridge-react wherever your app handles /auth/... paths. The router packages are optional peers: install only the one you use.

Auth method visibility (magic link, passkeys, SSO) is derived from your app’s configuration in the Control Center (your admin dashboard at app.thebridge.dev), so turning one on needs no code. The login form handles multi-step flows inline: forgot password, magic link requests, passkey login, MFA challenge, MFA setup, and workspace selection (a workspace is called a tenant in the API).

Climb only as far as you need:

  • Tokens: set --bridge-* CSS variables (see Theming).

  • Frame and heading: frame(page, children) replaces everything around the form on every page; heading(page) replaces each page’s main heading.

    <BridgeAuthRoutes
      frame={(page, children) => <main className="auth-card">{children}</main>}
      heading={(page) => <h1>{page === 'signup' ? 'Create your account' : 'Welcome back'}</h1>}
    />
    
  • Take over one page by passing an element for it; every other page keeps working:

    <BridgeAuthRoutes pages={{ login: <MyLoginPage /> }} />
    

    A login page you own navigates itself after sign-in, e.g. <LoginForm onLogin={() => navigate(readReturnTo(location.search) ?? '/')} />.

  • Headless: build your own UI on getBridgeAuth().

Other props: redirectTo (where a completed sign-in lands when there is no deep link, default /), messages (copy overrides), notFound (shown for an unknown address under /auth).

After a successful signup the user receives a verification email. Its link lands on /auth/set-password/<token>, which <BridgeAuthRoutes> already serves. Once verified, they can sign in.

See Theming & Styles for customization options.

The config object you pass to <BridgeProvider> is a BridgeConfig. Every field resolves as explicit option > environment > default. The most common fields:

FieldEnvironmentDefaultDescription
appIdVITE_BRIDGE_APP_ID(required)Your Bridge app ID. Missing everywhere, Bridge refuses to start and names the variable
apiBaseUrlVITE_BRIDGE_API_BASE_URLproductionOnly for a stage, local or self-hosted app
loginRouteVITE_BRIDGE_LOGIN_ROUTE(none: hosted login)Your in-app login page, e.g. /auth/login
defaultRedirectRouteVITE_BRIDGE_DEFAULT_REDIRECT_ROUTE'/'Route to land on after login
debugVITE_BRIDGE_DEBUGfalseEnable debug logging

Under Create React App the variables are REACT_APP_BRIDGE_*. See the Configuration reference for the full list (token storage, billing routes).