Skip to content

Pass your route rules to bridgeBootstrap in +layout.ts. The BridgeBootstrap component in +layout.svelte handles navigation guards automatically and renders your app only once Bridge is ready.

import { bridgeBootstrap } from '@nebulr-group/bridge-svelte';

export const ssr = false;

export const load = bridgeBootstrap({
  loginRoute: '/auth/login',
  rules: [
    { match: '/', public: true },
    { match: new RegExp('^/auth($|/)'), public: true },
    { match: '/beta/*', featureFlag: 'beta_feature', redirectTo: '/' },
  ],
  defaultAccess: 'protected',
});

How it works:

OptionWhat it does
defaultAccessSets whether unmatched routes are 'public' or 'protected'.
rulesMarks individual paths as public and/or gates them behind feature flags.
loginRouteUnauthenticated users are redirected here (an in-app route). If you leave it unset, they go to Bridge’s hosted login page instead.

Redirects are handled automatically by BridgeBootstrap. For the full RouteRule shape, including billing gates, see the config reference.

There are two guards, and they cover different moments:

GuardRunsCovers
load = bridgeBootstrap({ … }) in the root +layout.tsIn load, on every navigation (SvelteKit re-runs the root layout load whenever the URL changes)The first page load, client-side navigations, and redirects thrown by your own load functions — for example a public / whose +page.ts redirects into the app
<BridgeBootstrap> in the root +layout.svelteClient-side, once the layout has mountedClient-side navigations (a signed-out visitor is cancelled before the protected page loads), and re-checking the current page when a route flag, the plan, entitlements or the session change. It is not live during the first navigation of a page load — the load guard above covers that

Both fail closed: if a decision cannot be reached (a network error while evaluating a flag, broken route config), a protected route is denied rather than rendered. After a plan upgrade or sign-in, route verdicts are re-evaluated straight away rather than served from cache.

A second line of defence: assertAuthorized

Section titled “A second line of defence: assertAuthorized”

For pages that must never render for the wrong visitor, re-check the rules in the page’s own load. It throws the same redirect bridgeBootstrap would:

// src/routes/admin/+page.ts
import { assertAuthorized } from '@nebulr-group/bridge-svelte';
import type { PageLoad } from './$types';

export const load: PageLoad = async ({ url }) => {
  await assertAuthorized(url);
  // ...load the page's data
};

Someone who follows a link into a protected page — an emailed document link, a bookmark, a shared URL — lands on that page after signing in, not on your default route. This is on by default; you do not configure anything to get it.

How the target travels depends on which login you use:

ModeMechanismYour job
Hosted (no loginRoute)Held in sessionStorage across the OAuth round-tripNothing. It is automatic
SDK (you set loginRoute)?redirectUri= on your own login routeRead it after login — below

Your login page owns the post-login navigation, so it has to read the target. Use readReturnTo — it validates the value for you:

<script lang="ts">
  import { LoginForm, readReturnTo } from '@nebulr-group/bridge-svelte';
  import { goto } from '$app/navigation';
  import { page } from '$app/stores';

  function onLogin() {
    // Falls back to your own default when there is no target, or when the
    // one supplied is not safe to navigate to.
    goto(readReturnTo($page.url) ?? '/dashboard');
  }
</script>

<LoginForm {onLogin} />

Your loginRoute is excluded automatically, so a bounce through the login page never comes back pointing at itself. Exclude the rest of your auth flow too:

export const load = bridgeBootstrap({
  rules: [ /* … */ ],
  defaultAccess: 'protected',
  returnTo: {
    exclude: [new RegExp('^/auth($|/)')],
  },
});

To send every login to the same place regardless of where the visitor was heading:

returnTo: { enabled: false }

Public routes are never used as a return target, and neither is a path that fails validation — in both cases your login page gets null and falls back to its own default.