bridge Next.js Examples
Section titled “bridge Next.js Examples”Table of Contents
Section titled “Table of Contents”Authentication
Section titled “Authentication”Adding a Login Button
Section titled “Adding a Login Button”The simplest way to add login functionality to your app is to use the useAuth hook:
'use client';
import { useAuth } from '@nebulr-group/bridge-nextjs/client';
export default function LoginButton() { const { login, logout, isAuthenticated } = useAuth();
return ( <div> {isAuthenticated ? ( <button onClick={() => logout()}> Sign Out </button> ) : ( <button onClick={() => login()}> Sign In </button> )} </div> );}Route Protection
Section titled “Route Protection”bridge provides several ways to protect routes in your Next.js application:
Middleware Protection (Recommended)
Section titled “Middleware Protection (Recommended)”The most comprehensive way to protect routes is using the withBridgeAuth middleware:
import { withBridgeAuth } from '@nebulr-group/bridge-nextjs/server';
export default withBridgeAuth({ rules: [ { match: '/', public: true }, { match: '/login', public: true }, { match: '/about', public: true }, { match: '/auth/oauth-callback', public: true }, // All other routes are protected by default ]});
export const config = { matcher: [ '/((?!_next/static|_next/image|favicon.ico).*)', ]};This approach:
- Protects all routes by default (unless
defaultAccess: 'public'is set) - Allows you to specify public routes that don’t require authentication
- Handles redirects automatically
- Works with both client and server components
- Automatically reads configuration from environment variables
Component-Based Protection
Section titled “Component-Based Protection”For more granular control, you can use the ProtectedRoute component:
import { ProtectedRoute } from '@nebulr/bridge-nextjs';
export default function DashboardPage() { return ( <ProtectedRoute> <div> <h1>Dashboard</h1> <p>This content is only visible to authenticated users</p> </div> </ProtectedRoute> );}Server-Side Protection
Section titled “Server-Side Protection”For server components, you can use the ServerAuthCheck component:
import { ServerAuthCheck } from '@nebulr/bridge-nextjs/server';
export default function DashboardPage() { return ( <ServerAuthCheck redirectTo="/login"> <div> <h1>Dashboard</h1> <p>This content is only visible to authenticated users</p> </div> </ServerAuthCheck> );}Advanced Route Configuration
Section titled “Advanced Route Configuration”Understanding defaultAccess
Section titled “Understanding defaultAccess”By default, any route not specified in the rules array is protected (requires authentication). You can change this behavior with the defaultAccess parameter:
// Option 1: Protect by default (default behavior)export default withBridgeAuth({ defaultAccess: 'protected', // This is the default rules: [ { match: '/', public: true }, { match: '/login', public: true }, // All other routes require authentication ]});
// Option 2: Public by default, protect specific routesexport default withBridgeAuth({ defaultAccess: 'public', // All unmatched routes are public rules: [ { match: '/dashboard', public: false }, // Require auth for dashboard { match: '/profile', public: false }, // Require auth for profile // All other routes are public ]});Using Regular Expressions for Route Matching
Section titled “Using Regular Expressions for Route Matching”You can use regex patterns for more flexible route matching:
export default withBridgeAuth({ rules: [ { match: new RegExp('^/public'), public: true }, // All /public/* routes { match: new RegExp('^/api/public'), public: true }, // All public API routes { match: new RegExp('^/docs($|/)'), public: true }, // /docs and /docs/* routes ]});Configuring OAuth Callback URL
Section titled “Configuring OAuth Callback URL”After setting up your middleware, you need to configure the OAuth callback URL in the bridge Control Center:
- Go to the bridge Control Center
- Navigate to: Authentication → Authentication → Security
- Set the callback URL to match your application:
- Production:
https://your-app.com/auth/oauth-callback - Local Development:
http://localhost:3000/auth/oauth-callback
- Production:
The callback route is automatically handled by the withBridgeAuth middleware - no additional setup needed!
Note: Make sure to include the
/auth/oauth-callbackroute as public in your middleware rules, or it will be protected and authentication won’t work.
Renewing User Tokens
Section titled “Renewing User Tokens”bridge automatically handles token renewal for you. The token service will refresh tokens before they expire to ensure a seamless user experience.
// The token service handles renewal automatically// You can monitor token status with the useAuth hookimport { useAuth } from '@nebulr/bridge-nextjs';
function TokenStatus() { const { isAuthenticated, isLoading } = useAuth();
if (isLoading) return <div>Loading authentication status...</div>;
return ( <div> {isAuthenticated ? 'Authenticated' : 'Not authenticated'} </div> );}Checking if a User is Logged In
Section titled “Checking if a User is Logged In”You can use the useAuth hook to check if a user is currently logged in:
import { useAuth } from '@nebulr/bridge-nextjs';
function AuthStatus() { const { isAuthenticated, isLoading } = useAuth();
if (isLoading) return <div>Loading...</div>;
return ( <div> {isAuthenticated ? ( <div>You are logged in!</div> ) : ( <div>Please log in to continue</div> )} </div> );}Getting User Profile Information
Section titled “Getting User Profile Information”Access the current user’s profile information using the useAuth hook:
import { useAuth } from '@nebulr/bridge-nextjs';
function UserProfile() { const { user, isLoading } = useAuth();
if (isLoading) return <div>Loading profile...</div>;
if (!user) return <div>No user logged in</div>;
return ( <div> <h2>User Profile</h2> <p>Email: {user.email}</p> <p>Name: {user.name}</p> <p>ID: {user.id}</p> </div> );}Feature Flags
Section titled “Feature Flags”Bulk Fetching vs Live
Section titled “Bulk Fetching vs Live”bridge provides two ways to work with feature flags:
- Bulk Fetching (Recommended): Get all feature flags at once and use them throughout your application. This approach uses a 5-minute cache to improve performance.
- Live Updates: Check feature flags individually with real-time updates, bypassing the cache.
The recommended approach is to use bulk fetching with caching for better performance:
// Bulk fetching example - RECOMMENDED APPROACHimport { useFeatureFlagsContext } from '@nebulr/bridge-nextjs';
function FeatureFlagsPanel() { const { flags, refreshFlags } = useFeatureFlagsContext();
return ( <div> <button onClick={refreshFlags}>Refresh Flags</button> <ul> {Object.entries(flags).map(([key, enabled]) => ( <li key={key}> {key}: {enabled ? 'Enabled' : 'Disabled'} </li> ))} </ul> </div> );}When using the FeatureFlag component without the forceLive prop, it will use the cached values:
// Using cached feature flags (recommended for better performance)import { FeatureFlag } from '@nebulr/bridge-nextjs';
function CachedFeatureExample() { return ( <div> <h3>Cached Feature Flag</h3> <p>Uses cached values (5-minute cache)</p> <FeatureFlag flagName="demo-flag" fallback={<div>Feature flag "demo-flag" is disabled</div>} > <div> <p>Feature flag "demo-flag" is active</p> </div> </FeatureFlag> </div> );}For cases where you need real-time updates, you can use the forceLive prop:
// Live feature flag example (bypasses cache)import { FeatureFlag } from '@nebulr/bridge-nextjs';
function LiveFeatureExample() { return ( <div> <h3>Live Feature Flag</h3> <p>Direct API call on each load</p> <FeatureFlag flagName="demo-flag" forceLive={true} > <div> <p>Feature flag "demo-flag" is active</p> </div> </FeatureFlag> </div> );}If, else, if a featureflag is disabled then show this
Section titled “If, else, if a featureflag is disabled then show this”Use the FeatureFlag component with the negate prop to show content when a flag is disabled:
import { FeatureFlag } from '@nebulr/bridge-nextjs';
function ConditionalContent() { return ( <div> <FeatureFlag flagName="new-ui"> <div>New UI Content</div> </FeatureFlag>
<FeatureFlag flagName="new-ui" negate> <div>Legacy UI Content</div> </FeatureFlag> </div> );}You can also use the fallback prop to provide alternative content:
import { FeatureFlag } from '@nebulr/bridge-nextjs';
function FeatureWithFallback() { return ( <FeatureFlag flagName="premium-feature" fallback={<div>Upgrade to premium to access this feature</div>} > <div>Premium Feature Content</div> </FeatureFlag> );}Feature flags on routes
Section titled “Feature flags on routes”Protect entire routes with feature flags using middleware:
import { withFeatureFlags } from '@nebulr/bridge-nextjs/server';import { NextRequest } from 'next/server';
// Define feature flag protectionsconst featureFlagProtections = [ { flag: 'premium-feature', paths: ['/premium/*'], redirectTo: '/upgrade', }, { flag: 'beta-feature', paths: ['/beta/*'], redirectTo: '/', }];
// Create the middlewareconst featureFlagMiddleware = withFeatureFlags(featureFlagProtections);
// Export the middleware functionexport async function middleware(request: NextRequest) { return featureFlagMiddleware(request);}
// Configure which paths the middleware should run onexport const config = { matcher: [ '/((?!_next/static|_next/image|favicon.ico).*)', ]};Feature flags on server side code like apis
Section titled “Feature flags on server side code like apis”Use feature flags in server-side code, including API routes:
import { NextRequest, NextResponse } from 'next/server';import { isFeatureEnabledServer } from '@nebulr/bridge-nextjs/server';
export async function GET(request: NextRequest) { // Get the access token from the request const accessToken = request.headers.get('Authorization')?.replace('Bearer ', '');
if (!accessToken) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); }
// Check if the premium feature is enabled for this user const isPremiumEnabled = await isFeatureEnabledServer('premium-feature', accessToken);
if (!isPremiumEnabled) { return NextResponse.json( { error: 'This feature requires a premium subscription' }, { status: 403 } ); }
// Return premium data return NextResponse.json({ data: 'Premium content', message: 'You have access to premium features' });}Error Handling in Server-Side Code
Section titled “Error Handling in Server-Side Code”You can customize error handling for feature flag checks:
import { NextRequest, NextResponse } from 'next/server';import { isFeatureEnabledServer } from '@nebulr/bridge-nextjs/server';
export async function GET(request: NextRequest) { try { const accessToken = request.headers.get('Authorization')?.replace('Bearer ', '');
if (!accessToken) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); }
const isFeatureEnabled = await isFeatureEnabledServer('my-feature', accessToken);
if (!isFeatureEnabled) { // Custom error response return NextResponse.json( { error: 'Feature not available', code: 'FEATURE_DISABLED', message: 'This feature is currently disabled for your account' }, { status: 403 } ); }
return NextResponse.json({ data: 'Feature enabled content' }); } catch (error) { console.error('Feature flag error:', error); return NextResponse.json( { error: 'Internal server error' }, { status: 500 } ); }}Server-Side Rendering
Section titled “Server-Side Rendering”For feature flags in server components:
import { ServerFeatureFlag } from '@nebulr/bridge-nextjs/server';
export default function PremiumPage() { return ( <ServerFeatureFlag flagName="premium-feature" fallback={<div>Upgrade to premium to access this content</div>} > <div> <h1>Premium Content</h1> <p>This content is only visible to users with the premium feature enabled</p> </div> </ServerFeatureFlag> );}Configuration
Section titled “Configuration”Getting Config Values
Section titled “Getting Config Values”Access configuration values in your application:
import { useBridgeConfig } from '@nebulr/bridge-nextjs';
function ConfigDisplay() { const config = useBridgeConfig();
return ( <div> <h2>bridge Configuration</h2> <p>App ID: {config.appId}</p> <p>Auth Base URL: {config.authBaseUrl}</p> <p>Callback URL: {config.callbackUrl}</p> </div> );}Environment Variables
Section titled “Environment Variables”bridge configuration is primarily set through environment variables in your .env.local file.
Required Configuration
Section titled “Required Configuration”| Variable Name | Description |
|---|---|
NEXT_PUBLIC_BRIDGE_APP_ID | Your bridge application ID (get this from the Control Center → Keys) |
Optional Configuration
Section titled “Optional Configuration”All these settings have sensible defaults and are optional:
| Variable Name | Description | Default Value |
|---|---|---|
NEXT_PUBLIC_BRIDGE_AUTH_BASE_URL | Base URL for bridge auth services | https://api.thebridge.dev/auth |
NEXT_PUBLIC_BRIDGE_CALLBACK_URL | Custom OAuth callback URL | Auto-determined from origin |
NEXT_PUBLIC_BRIDGE_DEFAULT_REDIRECT_ROUTE | Route to redirect to after login | / |
NEXT_PUBLIC_BRIDGE_LOGIN_ROUTE | Route for login page | /login |
NEXT_PUBLIC_BRIDGE_TEAM_MANAGEMENT_URL | URL for team management portal | bridge default portal |
NEXT_PUBLIC_BRIDGE_DEBUG | Enable debug logging | false |
Example Configuration Files
Section titled “Example Configuration Files”Minimal .env.local (recommended):
# Only the app ID is required - everything else uses defaultsNEXT_PUBLIC_BRIDGE_APP_ID=your-app-id-hereFull .env.local (with all optional settings):
# RequiredNEXT_PUBLIC_BRIDGE_APP_ID=your-app-id-here
# Optional: Custom auth base URLNEXT_PUBLIC_BRIDGE_AUTH_BASE_URL=https://api.thebridge.dev/auth
# Optional: Custom callback URLNEXT_PUBLIC_BRIDGE_CALLBACK_URL=/auth/oauth-callback
# Optional: Default redirect route after loginNEXT_PUBLIC_BRIDGE_DEFAULT_REDIRECT_ROUTE=/dashboard
# Optional: Login route for unauthenticated usersNEXT_PUBLIC_BRIDGE_LOGIN_ROUTE=/auth/login
# Optional: Team management portal URLNEXT_PUBLIC_BRIDGE_TEAM_MANAGEMENT_URL=https://api.thebridge.dev/cloud-views/user-management-portal/users
# Optional: Enable debug mode for detailed loggingNEXT_PUBLIC_BRIDGE_DEBUG=trueConfiguration Priority: Environment variables take highest priority, followed by props passed to the provider, then default values.
Additional Configs
Section titled “Additional Configs”You can also provide configuration directly through props (though environment variables are recommended):
Passing appId as a Prop
Section titled “Passing appId as a Prop”import { BridgeProvider } from '@nebulr-group/bridge-nextjs/client';
export default function RootLayout({ children }: { children: React.ReactNode }) { return ( <html lang="en"> <body> <BridgeProvider appId={process.env.NEXT_PUBLIC_BRIDGE_APP_ID!}> {children} </BridgeProvider> </body> </html> );}Passing Full Config Object
Section titled “Passing Full Config Object”import { BridgeProvider } from '@nebulr-group/bridge-nextjs/client';
export default function RootLayout({ children }: { children: React.ReactNode }) { return ( <html lang="en"> <body> <BridgeProvider config={{ appId: 'your-app-id', callbackUrl: '/custom-callback', defaultRedirectRoute: '/dashboard', loginRoute: '/signin', debug: true }} > {children} </BridgeProvider> </body> </html> );}Middleware Configuration
Section titled “Middleware Configuration”Similarly, you can pass configuration to the middleware:
import { withBridgeAuth } from '@nebulr-group/bridge-nextjs/server';
export default withBridgeAuth({ appId: 'your-app-id', // Optional - reads from NEXT_PUBLIC_BRIDGE_APP_ID by default debug: true, // Optional - enable debug logging rules: [ { match: '/', public: true }, ]});Note: Environment variables take highest priority. If both an environment variable and a prop are provided, the environment variable will be used.