Examples
Section titled “Examples”End-to-end, copy-pasteable examples for the Bridge NestJS plugin. Every snippet compiles against the current API. For conceptual depth, follow the links to the topic guides.
- Authentication & Access Control
- Configuration
- Feature Flags
- Tenant data via
BridgeService - Multi-Tenancy
- Frontend Integration
- Error Handling
1. Module setup with a global guard
Section titled “1. Module setup with a global guard”import { Module } from '@nestjs/common';
import { BridgeModule } from '@nebulr-group/bridge-nestjs';
@Module({
imports: [
BridgeModule.forRoot({
appId: process.env.BRIDGE_APP_ID!,
guard: {
global: true,
defaultAccess: 'protected',
rules: [
{ path: '/health', privilege: 'ANONYMOUS' },
{ path: '/webhooks/*', privilege: 'ANONYMOUS' },
{ path: '/account/users', privilege: 'AUTHENTICATED', featureFlag: 'manage-users' },
],
},
}),
],
})
export class AppModule {}
Async variant (reading config from @nestjs/config):
BridgeModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (config: ConfigService) => ({
appId: config.get('BRIDGE_APP_ID'),
debug: config.get('BRIDGE_DEBUG') === 'true',
}),
});
2. Reading the current user and tenant
Section titled “2. Reading the current user and tenant”import { Controller, Get, UseGuards } from '@nestjs/common';
import {
BridgeAuthGuard,
CurrentUser,
CurrentTenant,
BridgeUser,
BridgeTenant,
} from '@nebulr-group/bridge-nestjs';
@Controller('me')
@UseGuards(BridgeAuthGuard)
export class MeController {
@Get()
whoAmI(@CurrentUser() user: BridgeUser, @CurrentTenant() tenant: BridgeTenant) {
return {
userId: user.id,
email: user.email,
role: user.role,
privileges: user.privileges, // ['AUTHENTICATED', 'USER_READ', ...]
tenantId: tenant.id,
tenantName: tenant.name,
};
}
}
3. Who gets an endpoint: a flag
Section titled “3. Who gets an endpoint: a flag”Every gate is a flag, and the flag’s rule says why. admin-area is ruled on a
privilege, e.g. privileges contains "USER_WRITE" (ADMIN and OWNER hold it in
the default setup; read the app’s real roles with list_roles /
bridge role list). The code never reads the role.
import { Controller, Get, UseGuards } from '@nestjs/common';
import { BridgeAuthGuard, RequireFeatureFlag } from '@nebulr-group/bridge-nestjs';
@Controller('admin')
@UseGuards(BridgeAuthGuard)
@RequireFeatureFlag('admin-area') // applies to the whole controller
export class AdminController {
@Get('settings')
@RequireFeatureFlag('admin-settings') // its own flag, e.g. privileges contains "TENANT_WRITE"
getSettings() { ... }
}
4. API tokens, privileges, and @AcceptAuth
Section titled “4. API tokens, privileges, and @AcceptAuth”import { Controller, Get, UseGuards } from '@nestjs/common';
import { BridgeAuthGuard, RequirePrivilege, AcceptAuth } from '@nebulr-group/bridge-nestjs';
// Machine-to-machine endpoint: only an API token (x-api-key) is accepted.
@Controller('integrations/users')
@AcceptAuth('api_token')
@UseGuards(BridgeAuthGuard)
export class IntegrationUsersController {
@Get()
@RequirePrivilege('USER_READ') // API tokens only: the scope an x-api-key caller must carry
list() { ... }
}
5. Public routes
Section titled “5. Public routes”import { Controller, Get } from '@nestjs/common';
import { Public } from '@nebulr-group/bridge-nestjs';
@Controller('health')
export class HealthController {
@Get()
@Public()
check() {
return { status: 'ok' };
}
}
6. Feature flags
Section titled “6. Feature flags”Live-updating: @RequireFlag / @Flag
Section titled “Live-updating: @RequireFlag / @Flag”import { Controller, Get, UseGuards } from '@nestjs/common';
import { BridgeFlagGuard, RequireFlag, Flag } from '@nebulr-group/bridge-nestjs/flags';
@Controller('beta')
@UseGuards(BridgeFlagGuard)
export class BetaController {
@Get('feature-x')
@RequireFlag('feature_x') // 403 when the flag is off
getFeatureX() { ... }
@Get('home')
home(@Flag({ key: 'show_new_home', defaultValue: false }) showNew: boolean) {
// NOTE: @Flag takes ONE object argument { key, defaultValue }, not positional args.
return showNew ? this.newHome() : this.oldHome();
}
}
On-demand: @RequireFeatureFlag + FeatureFlagService
Section titled “On-demand: @RequireFeatureFlag + FeatureFlagService”import { Controller, Get, Injectable } from '@nestjs/common';
import { RequireFeatureFlag, FeatureFlagService } from '@nebulr-group/bridge-nestjs';
@Controller('premium')
export class PremiumController {
@Get()
@RequireFeatureFlag({ all: ['premium-tier', 'active-subscription'] })
getPremium() { ... }
}
@Injectable()
export class ReportsService {
constructor(private readonly featureFlags: FeatureFlagService) {}
async generate(accessToken: string) {
return (await this.featureFlags.isEnabled('pdf-export', accessToken))
? this.generatePdf()
: this.generateBasic();
}
}
7. Tenant data, and a feature a plan sells
Section titled “7. Tenant data, and a feature a plan sells”The plan feature is gated by a flag: list pdf-export on the plans that sell it
(bridge plan feature add pro pdf_export) and rule the flag
bridge:billing.entitlement.pdf_export eq true. A workspace without it gets
402 FEATURE_NOT_IN_PLAN with the upgrade route.
import { Controller, Get, Req, UseGuards } from '@nestjs/common';
import type { Request } from 'express';
import { BridgeAuthGuard, BridgeService, RequireFeatureFlag } from '@nebulr-group/bridge-nestjs';
@Controller('reports')
@UseGuards(BridgeAuthGuard)
export class ReportsController {
constructor(private readonly bridge: BridgeService) {}
@Get('export')
@RequireFeatureFlag('pdf-export')
async export(@Req() req: Request) {
const tenant = this.bridge.fromRequest(req); // the token BridgeAuthGuard verified
const sub = await tenant.subscription; // { plan: { slug, name }, status, endsAt?, gateEngaged? }
return this.buildExport(sub.plan.slug);
}
}
See Tenant data via BridgeService for the full reference.
8. Token forwarding between microservices
Section titled “8. Token forwarding between microservices”import { Controller, Get, Req } from '@nestjs/common';
import { BridgeHttpService } from '@nebulr-group/bridge-nestjs';
import { Request } from 'express';
@Controller('items')
export class ItemsController {
constructor(private readonly http: BridgeHttpService) {}
@Get('from-service-b')
async getFromServiceB(@Req() req: Request) {
// Forwards the verified user token so service-b authenticates the same user.
return this.http.get('http://service-b/items', req.bridgeAccessToken);
}
}
9. Public webhook handler (multi-tenant)
Section titled “9. Public webhook handler (multi-tenant)”import { Controller, Post, Body } from '@nestjs/common';
import { Public } from '@nebulr-group/bridge-nestjs';
@Controller('webhooks')
export class WebhooksController {
@Post('bridge')
@Public() // webhooks carry no user JWT
async handle(@Body() event: { type: string; tenantId: string }) {
// Resolve tenant from the event payload, then act on it.
return { received: true };
}
}