Require authentication in controllers
The @Authentication decorator
The @Authentication decorator retrieves and validates a token from x-antelopejs-auth, or from the ANTELOPEJS_AUTH cookie when the header is absent, and injects the verified payload into the parameter.
import { Controller, Get } from "@antelopejs/interface-api";
import { Authentication } from "@antelopejs/interface-auth";
class UserController extends Controller("/users") {
@Get("profile")
async getProfile(@Authentication() user: { id: string; name: string }) {
return {
id: user.id,
name: user.name,
};
}
}
If the token is missing or invalid, the request fails with an error response before the handler executes.
The payload annotations in these examples describe the application's expected token format. They do not check it. Add a shape-checking verifier before reading claims from tokens whose format is not already enforced. The API provider determines how ordinary thrown errors become HTTP responses; throwing Error does not itself specify a 401 or 403 status.
Inline validators
Pass a validator function directly to the @Authentication decorator for one-off validation logic.
import { Controller, Post } from "@antelopejs/interface-api";
import { Authentication } from "@antelopejs/interface-auth";
class PaymentController extends Controller("/payments") {
@Post()
async createPayment(
@Authentication((user: any) => {
if (!user.paymentPermissions) {
throw new Error("Payment permissions required");
}
return user;
})
user: any,
) {
// Process payment
return { success: true };
}
}
Create custom decorators with CreateAuthDecorator
The CreateAuthDecorator function creates a reusable authentication decorator with custom source, authenticator, and validator functions.
import { CreateAuthDecorator } from "@antelopejs/interface-auth";
import type { IncomingMessage } from "node:http";
// Admin-only decorator
export const AdminAuth = CreateAuthDecorator({
validator: (user: any) => {
if (!user || user.role !== "admin") {
throw new Error("Admin access required");
}
return user;
},
});
// API key decorator with custom source and authenticator
export const ApiKeyAuth = CreateAuthDecorator({
source: (req: IncomingMessage) => {
const key = req.headers["x-api-key"];
return typeof key === "string" ? key : undefined;
},
authenticator: async (apiKey?: string) => {
if (!apiKey) throw new Error("API key required");
const user = await validateApiKey(apiKey);
if (!user) throw new Error("Invalid API key");
return user;
},
});
validateApiKey is your application's lookup and verification function. Returning null for a missing or invalid key would allow the handler to run with null; this example throws instead.
CreateAuthDecorator options
The function accepts an object with the following properties:
| Property | Type | Description |
|---|---|---|
source | AuthSource | Extracts the token from the request (defaults to header/cookie) |
authenticator | AuthVerifier<T> | Verifies the token and returns the payload |
authenticatorOptions | VerifyOptions | Options passed to the authenticator |
validator | AuthValidator<T, R> | Validates and transforms the authenticated data |
All properties are optional. The default source reads the header/cookie, the default authenticator calls ValidateRaw, and the default verification options are {}. Without a validator, the verified payload is passed through unchanged.
A validator passed to a decorator call replaces the configured validator; the two do not compose. Return a transformed value to inject it, or throw to deny access. Returning false or null does not reject the request. A custom authenticator that accepts a missing token also permits it unless a validator throws.
Class-level authentication
The @Authentication decorator can be applied to an entire controller class. This ensures that all routes within that controller require authentication, without decorating each handler individually.
import { Controller, Get, Post } from "@antelopejs/interface-api";
import { Authentication } from "@antelopejs/interface-auth";
@Authentication()
class UserController extends Controller("/users") {
@Get("profile")
async getProfile() {
// Only authenticated users can access this endpoint
return { message: "Authenticated profile access" };
}
@Post("settings")
async updateSettings() {
// This route is also protected
return { success: true };
}
}
Class-level with role-based access
Combine class-level authentication with a validator to enforce role-based access for all routes in a controller.
import { Controller } from "@antelopejs/interface-api";
import { Authentication } from "@antelopejs/interface-auth";
@Authentication((user: any) => {
if (!user || user.role !== "admin") {
throw new Error("Admin access required");
}
return user;
})
class AdminController extends Controller("/admin") {
// All routes require admin authentication
}
Property-level authentication
Apply @Authentication to a class property to access the authenticated user data throughout the controller. The property is populated automatically for each request.
import { Controller, Get } from "@antelopejs/interface-api";
import { Authentication } from "@antelopejs/interface-auth";
class UserController extends Controller("/users") {
@Authentication()
private user!: { id: string; name: string };
@Get("profile")
async getProfile() {
return {
id: this.user.id,
name: this.user.name,
};
}
@Get("settings")
async getSettings() {
// The same user data is available in all handlers
return { userId: this.user.id, theme: "dark" };
}
}
Decorator scope summary
The @Authentication decorator (and any custom decorator created with CreateAuthDecorator) can be applied at three levels:
| Scope | Effect |
|---|---|
| Parameter | Injects the verified payload into a single handler parameter |
| Property | Populates a class property with the verified payload for all handlers |
| Class | Requires authentication for every route in the controller |