Guards
Guard interface and usage for TypeScript and Python
Guards control access to tools, resources, and prompts by determining whether a request should proceed. They implement authorization logic, verify authentication tokens, check permissions, and enforce access policies.
Guards execute before the handler and can deny access by returning false or throwing an exception.
Guard Interface
A guard has one method. Return true to let the call continue; return false or throw to stop it.
interface Guard {
canActivate(context: ExecutionContext): Promise<boolean> | boolean;
}async def can_activate(self, context: ExecutionContext) -> boolStack with @use_guards. Built-ins: ApiKeyGuard, JwtGuard, OAuthGuard.
from nitrostack import use_guards, OAuthGuard, ApiKeyGuard, JwtGuard
@use_guards(OAuthGuard)
async def search_flights(...):
...Scaffold: nitrostack-py generate guard MyGuard.
Read tokens from context.metadata (authorization, headers, _oauth). OAuthGuard allows no-token when OAUTH_REQUIRED is unset.
Parameters:
context: The execution context containing auth data, logger, and metadata
Returns:
true: Allow the request to proceedfalse: Deny access (throws ForbiddenException)throw Error: Deny access with custom error
Using Guards
Attach guards with @UseGuards. When you list several, they run in order and all of them must pass.
On Individual Methods
Put @UseGuards on the handler it protects.
import { ToolDecorator as Tool, UseGuards, ExecutionContext } from '@nitrostack/core';
import { AuthGuard } from './guards/auth.guard.js';
export class UserTools {
@Tool({ name: 'get_profile' })
@UseGuards(AuthGuard)
async getProfile(input: {}, ctx: ExecutionContext) {
return this.userService.findById(ctx.auth!.subject);
}
}Multiple Guards
Guards execute in order. All must pass for the request to proceed:
@Tool({ name: 'delete_user' })
@UseGuards(AuthGuard, AdminGuard, RateLimitGuard)
async deleteUser(input: { userId: string }, ctx: ExecutionContext) {
// Only authenticated admins within rate limit can access
return this.userService.delete(input.userId);
}On Resources and Prompts
Guards work on all MCP primitives:
@Resource({
uri: 'admin://dashboard',
name: 'Admin Dashboard'
})
@UseGuards(AdminGuard)
async getAdminDashboard(uri: string, ctx: ExecutionContext) {
// Admin-only resource
}
@Prompt({
name: 'confidential_analysis',
title: 'Confidential Analysis',
description: 'Analyze confidential data'
})
@UseGuards(OfficerClearanceGuard)
async getConfidentialPrompt(args: any, ctx: ExecutionContext) {
// Officer-level prompt
}Dependency Injection
Guards can inject services:
@Injectable({ deps: [UserService, ConfigService] })
export class SubscriptionGuard implements Guard {
constructor(
private userService: UserService,
private configService: ConfigService
) {}
async canActivate(context: ExecutionContext): Promise<boolean> {
const userId = context.auth?.subject;
if (!userId) return false;
const user = await this.userService.findById(userId);
if (!user) return false;
const requiredPlan = this.configService.get('REQUIRED_PLAN', 'pro');
if (user.subscriptionPlan !== requiredPlan && user.subscriptionPlan !== 'enterprise') {
context.logger.info('Subscription check failed', {
userId,
userPlan: user.subscriptionPlan,
requiredPlan
});
return false;
}
return true;
}
}Guard patterns
Worked examples are split by what the guard checks.
Custom Guards
Role, permission, and clearance checks.
Authentication Guards
Validate JWTs and API keys.
Access Rules
Rate limits, time windows, and conditions.
Tools Guide
Using guards with tools.
Resources Guide
Protected resources.
Middleware Guide
Middleware pipeline.
Authentication Overview
Auth patterns.
API Key Authentication
API key guards.
OAuth Authentication
OAuth guards.
