This repository contains both Bridge Svelte library and a demo application showcasing its features.
npm install @nebulr-group/bridge-svelte
The Bridge SvelteKit SDK is configured by passing a BridgeConfig object to the bridgeBootstrap function in your root +layout.ts file.
Here's an example:
import { bridgeBootstrap, type BridgeConfig } from '@nebulr-group/bridge-svelte';
export const load = async ({ url }) => {
const config: BridgeConfig = {
appId: 'your_app_id',
callbackUrl: 'http://localhost:5173/auth/oauth-callback',
defaultRedirectRoute: '/protected',
debug: true,
};
await bridgeBootstrap(url, config);
};
These are the primary options you will need to configure for your application.
appId (required string): Your unique application identifier from the Bridge dashboard.callbackUrl (string): The URL that Bridge will redirect to after a user successfully authenticates.window.location.origin + '/auth/oauth-callback'defaultRedirectRoute (string): The route to redirect users to after a successful login.'/'debug (boolean): Set to true to enable detailed logging from the Bridge SDK to the console.falseThese options are typically only needed for development or advanced use cases. In most production scenarios, you can rely on their default values.
apiBaseUrl (string): The root URL of the Bridge API. All service URLs are derived from this.'https://api.thebridge.dev'loginRoute (string): The route within your application that serves as the login page. The SDK will redirect users here if they attempt to access a protected route without being authenticated.'/login'Bridge supports two authentication modes. Choose the one that fits your needs:
The zero-config approach. Users are redirected to Bridge's hosted login page (cloud-views) and returned via OAuth callback. No custom UI needed.
<!-- Just add the Login button — Bridge handles the rest -->
<script>
import { Login } from '@nebulr-group/bridge-svelte';
</script>
<Login />
You also need an OAuth callback page at /auth/oauth-callback:
<!-- src/routes/auth/oauth-callback/+page.svelte -->
<p>Signing you in...</p>
The bridgeBootstrap() function in your +layout.ts automatically detects the callback and exchanges the code for tokens.
Best for: Quick setup, hosted auth page, minimal customization needed.
For more details, see:
Full auth UI runs on your domain — no redirects. Users never leave your app. Supports password login, SSO, MFA, passkeys, magic links, signup, and password reset.
<script>
import { LoginForm } from '@nebulr-group/bridge-svelte';
</script>
<LoginForm
showSignupLink
signupHref="/signup"
onLogin={() => goto('/dashboard')}
/>
<LoginForm /> is a compound component that handles the entire flow: email → password → MFA → tenant selection. It uses the authState store internally, so transitions happen automatically.
You can also use individual components for custom flows:
<script>
import {
MfaChallenge,
MfaSetup,
TenantSelector,
SsoButton,
SignupForm,
ForgotPassword,
MagicLink,
PasskeyLogin,
PasskeySetup,
} from '@nebulr-group/bridge-svelte';
</script>
Best for: Custom domain, white-label, full UI control, zero redirects.
| Component | Purpose | Key Props |
|---|---|---|
<LoginForm /> |
Full multi-step login | showSignupLink, showForgotPassword, showMagicLink, showPasskeys, onLogin, heading |
<SignupForm /> |
Registration form | onSignup, showLoginLink, loginHref |
<MfaChallenge /> |
MFA code entry + recovery | onVerified, showRecoveryOption |
<MfaSetup /> |
Phone → verify → backup code | onComplete |
<TenantSelector /> |
Multi-tenant workspace picker | onSelect, tenantItem (custom render snippet) |
<SsoButton /> |
Federation popup (Google, Azure, etc.) | connection, label, icon (snippet) |
<ForgotPassword /> |
Send reset link / set new password | token (if present, shows set-password form), loginHref |
<MagicLink /> |
Passwordless email link | onSent, loginHref |
<PasskeyLogin /> |
WebAuthn authentication | onLogin, autofill |
<PasskeySetup /> |
WebAuthn registration (from email link) | token, onComplete |
All SDK auth components use CSS custom properties with sensible defaults. Override in your global CSS:
:root {
--bridge-primary: #3b82f6;
--bridge-primary-hover: #2563eb;
--bridge-error: #ef4444;
--bridge-success: #22c55e;
--bridge-border: #e5e7eb;
--bridge-text: #1f2937;
--bridge-text-muted: #6b7280;
--bridge-bg: #ffffff;
--bridge-radius: 0.375rem;
--bridge-font-family: inherit;
}
| OAuth Redirect | SDK Auth | |
|---|---|---|
| Login UI | Hosted by Bridge | Your app |
| Redirects | 6+ (OAuth flow) | 0 |
| Custom domain | No | Yes |
| UI customization | Branding only | Full control |
| Setup effort | Minimal | Add components + routes |
| SSO | Full redirect chain | 1 popup |
| MFA | Handled by Bridge | <MfaChallenge /> / <MfaSetup /> |
Both modes use the same Bridge API, same tokens, same feature flags, same route guards. You can even use both in the same app (e.g., OAuth redirect for SSR pages, SDK auth for SPA pages).
profileStore)For feature flag examples and implementation details, see:
The library supports:
For full examples and API reference, see:
Quick start:
<script lang="ts">
import { PlanSelector, loadSubscription } from '@nebulr-group/bridge-svelte';
import { onMount } from 'svelte';
onMount(() => loadSubscription());
</script>
<PlanSelector
successUrl="https://yourapp.com/subscription/success"
cancelUrl="https://yourapp.com/subscription/cancel"
/>
The library provides:
<PlanSelector> — drop-in headless component that renders plan cards and drives the full checkout flowsubscriptionStore — reactive Svelte store with status, plans, loading, errorloadSubscription() — fetches status + plans in parallel and populates the storeplanService methods for custom UIs: getPlans, getSubscriptionStatus, selectFreePlan, startCheckout, changePlan, getPortalUrl@stripe/stripe-js (install separately, only needed for paid plans)The demo application in this repository contains runnable examples of Bridge usage patterns found in the examples documentation.
To run bridge demo:
# From bridge project root
bun install
bun run dev
The demo showcases:
/sdk-auth/* pages with embedded <LoginForm />, <SignupForm />, etc. (no redirects)E2E tests run against the demo app using Playwright. The tests verify authentication flows, route protection, feature flags, and team management.
Copy the env template and fill in the API key:
cp config/.env.test.local.example config/.env.test.local
Set PLAYWRIGHT_TEST_API_KEY in config/.env.test.local (same key as in bridge-api's config)
That's it. The test app and demo env files are configured automatically.
The pre-setup script creates the test app automatically, but you can also set up the dedicated SDK test app manually via the bridge-api endpoint (idempotent — safe to run repeatedly):
curl -X POST http://localhost:3200/v1/account/test/playwright/setup-sdk-app \
-H "Content-Type: application/json" \
-H "x-playwright-api-key: $PLAYWRIGHT_TEST_API_KEY"
This creates a fixed SDK app with a stable app ID that you can hardcode in demo/.env.test.local:
VITE_BRIDGE_APP_ID=69b2b2e2d4171d4fcdc7ef25
See bridge-api's README → "SDK App Setup" for full details.
# Run all tests against local bridge-api (starts demo app automatically)
bun run test:e2e
# Run a single test file
bun run test:e2e -- e2e/playwright/tests/auth/login-logout.spec.ts
# Run tests matching a name pattern
bun run test:e2e -- --grep "login"
# Run in headed mode (see the browser)
bun run test:e2e:headed
# Run against staging bridge backend
bun run test:e2e:stage
# Run against production bridge backend
bun run test:e2e:prod
# View test report
bun run test:e2e:report
Each command automatically:
e2e/playwright/pre-setup.ts) creates the test app via bridge-api and writes VITE_BRIDGE_APP_ID into the demo env file before Playwright startswebServer config with the correct Vite mode (--mode test.local, --mode test.stage, or --mode test.prod)BRIDGE_SVELTE_TEST_DASHBOARD) via bridge-api — completely separate from the Bridge admin appBridge Svelte is published automatically to npm through a GitHub Action workflow.
To publish a new package version:
Update the version field in bridge-svelte/package.json
Commit and push your changes to a feature branch
Create pull request and merge into main
Tag the release using semantic versioning (vX.Y.Z):
git tag v1.2.3
git push origin v1.2.3
We welcome contributions! Please see our Contributing Guide for details.
This project is licensed under the MIT License - see the LICENSE file for details.