@bulwark/nestjs

NestJS module for Bulwark — guards, decorators, and service injection.

Installation

npm install @bulwark/nestjs

Module Setup

// app.module.ts
import { BulwarkModule } from "@bulwark/nestjs";

@Module({
  imports: [
    BulwarkModule.forRoot({
      tenantId: process.env.BULWARK_TENANT_ID,
      apiKey: process.env.BULWARK_API_KEY,
      baseUrl: process.env.BULWARK_BASE_URL,
    }),
  ],
})
export class AppModule {}

Guards

JWT Auth Guard

import { Controller, Get, UseGuards } from "@nestjs/common";
import { BulwarkAuthGuard, CurrentUser } from "@bulwark/nestjs";

@Controller("profile")
@UseGuards(BulwarkAuthGuard)
export class ProfileController {
  @Get()
  getProfile(@CurrentUser() user: BulwarkUser) {
    return user;
  }
}

Agent Guard

import { BulwarkAgentGuard, RequiredScopes } from "@bulwark/nestjs";

@Controller("data")
@UseGuards(BulwarkAgentGuard)
export class DataController {
  @Get()
  @RequiredScopes("read:data")
  getData() {
    return { data: "..." };
  }
}

Service Injection

import { Injectable } from "@nestjs/common";
import { BulwarkService } from "@bulwark/nestjs";

@Injectable()
export class AgentService {
  constructor(private readonly bulwark: BulwarkService) {}

  async registerAgent(name: string) {
    return this.bulwark.agents.register({
      name,
      scopes: ["read:data"],
      trustLevel: "medium",
    });
  }

  async createSession(agentId: string, userId: string) {
    return this.bulwark.sessions.create({
      agentId,
      userId,
      requestedScopes: ["read:data"],
    });
  }
}

Decorators

@CurrentUser()

Injects the authenticated user into the handler:

@Get("me")
@UseGuards(BulwarkAuthGuard)
me(@CurrentUser() user: BulwarkUser) {
  return user;
}

@CurrentAgent()

Injects the authenticated agent:

@Post("task")
@UseGuards(BulwarkAgentGuard)
runTask(@CurrentAgent() agent: BulwarkAgent) {
  console.log(agent.agentId);
}

@RequiredScopes(...scopes)

Enforces scope requirements on the route:

@Get("sensitive")
@UseGuards(BulwarkAgentGuard)
@RequiredScopes("read:sensitive", "audit:write")
sensitiveData() { ... }

Async Configuration

BulwarkModule.forRootAsync({
  imports: [ConfigModule],
  useFactory: (config: ConfigService) => ({
    tenantId: config.get("BULWARK_TENANT_ID"),
    apiKey: config.get("BULWARK_API_KEY"),
  }),
  inject: [ConfigService],
})