From c4e52cf1f940f077696b1e50a9d11d8f7f75b01a Mon Sep 17 00:00:00 2001 From: David Mytton Date: Wed, 18 Dec 2024 20:25:17 +0000 Subject: [PATCH] chore: Update user agent header examples (#326) --- src/content/docs/bot-protection/concepts.mdx | 32 ++++++++++++++++--- src/content/docs/reference/nestjs.mdx | 3 +- src/content/docs/reference/nodejs.mdx | 24 ++++++++++---- src/content/docs/reference/remix.mdx | 17 +++++++--- .../bot-protection/reference/bun/Errors.js | 22 ++++++++----- .../bot-protection/reference/bun/Errors.ts | 22 ++++++++----- .../bot-protection/reference/deno/Errors.ts | 22 ++++++++----- .../bot-protection/reference/nestjs/Errors.ts | 3 +- .../reference/nextjs/ErrorsApp.js | 22 ++++++++----- .../reference/nextjs/ErrorsApp.ts | 22 ++++++++----- .../reference/nextjs/ErrorsPages.js | 22 ++++++++----- .../reference/nextjs/ErrorsPages.ts | 22 ++++++++----- .../bot-protection/reference/nodejs/Errors.js | 25 +++++++++------ .../bot-protection/reference/nodejs/Errors.ts | 25 +++++++++------ .../bot-protection/reference/remix/Errors.js | 22 ++++++++----- .../bot-protection/reference/remix/Errors.ts | 22 ++++++++----- .../reference/sveltekit/Errors.js | 22 ++++++++----- .../reference/sveltekit/Errors.ts | 22 ++++++++----- .../reference/sveltekit/ErrorHandling.js | 3 +- .../reference/sveltekit/ErrorHandling.ts | 3 +- .../shield/reference/nestjs/Errors.ts | 15 ++------- .../signup-protection/reference/bun/Errors.js | 18 ++++++++--- .../signup-protection/reference/bun/Errors.ts | 18 ++++++++--- .../reference/nestjs/Errors.ts | 3 +- .../reference/nextjs/ErrorHandlingApp.js | 18 ++++++++--- .../reference/nextjs/ErrorHandlingApp.ts | 18 ++++++++--- .../reference/nextjs/ErrorHandlingPages.js | 18 ++++++++--- .../reference/nextjs/ErrorHandlingPages.ts | 17 ++++++++++ .../reference/nodejs/Errors.js | 21 +++++++++--- .../reference/nodejs/Errors.ts | 21 +++++++++--- .../reference/remix/Errors.js | 19 ++++++++--- .../reference/remix/Errors.ts | 19 ++++++++--- .../reference/sveltekit/Errors.js | 18 ++++++++--- .../reference/sveltekit/Errors.ts | 18 ++++++++--- 34 files changed, 431 insertions(+), 187 deletions(-) diff --git a/src/content/docs/bot-protection/concepts.mdx b/src/content/docs/bot-protection/concepts.mdx index 2cb5d2ab..545ccf71 100644 --- a/src/content/docs/bot-protection/concepts.mdx +++ b/src/content/docs/bot-protection/concepts.mdx @@ -40,17 +40,39 @@ possible to achieve 100% accuracy. Requests without `User-Agent` headers can not be identified as any particular bot and will be marked as an errored decision. Check `decision.isErrored()` and -decide if you want to allow or deny the request. Our recommendation is to block -requests without `User-Agent` headers because most legitimate clients always -send this header. +decide if you want to allow or deny the request. + +Our recommendation is to block requests without `User-Agent` headers before +calling Arcjet because most legitimate clients always send this header: + +```ts +if (!request.headers.get("User-Agent")) { + log.warn("request missing required user-agent header"); + // Return a 400 Bad request error here + // Next.js example: + // return NextResponse.json({ error: "Bad request" }, { status: 400 }); + // Node.js example: + // res.writeHead(400, { "Content-Type": "application/json" }); + // res.end(JSON.stringify({ error: "Bad request" })); +} +``` + +An alternative approach is to check the error message after the decision is +made: ```ts if (decision.isErrored()) { - if (decision.reason.message.includes("missing User-Agent header")) { - log.warn({ error: decision.reason.message }, "Arcjet user-agent warning"); + if (decision.reason.message.includes("requires user-agent header")) { + log.warn( + { error: decision.reason.message }, + "request missing required user-agent header", + ); // You could return a 400 Bad request error here // Next.js example: // return NextResponse.json({ error: "Bad request" }, { status: 400 }); + // Node.js example: + // res.writeHead(400, { "Content-Type": "application/json" }); + // res.end(JSON.stringify({ error: "Bad request" })); } else { // Just log the error and continue log.error({ error: decision.reason.message }, "Arcjet error"); diff --git a/src/content/docs/reference/nestjs.mdx b/src/content/docs/reference/nestjs.mdx index 73696d55..a2bb5da2 100644 --- a/src/content/docs/reference/nestjs.mdx +++ b/src/content/docs/reference/nestjs.mdx @@ -373,11 +373,12 @@ If there is an error condition, Arcjet will return an `ERROR` `conclusion`. ```ts if (decision.isErrored()) { - if (decision.reason.message.includes("missing User-Agent header")) { + if (decision.reason.message.includes("requires user-agent header")) { // Requests without User-Agent headers can not be identified as any // particular bot and will be marked as an errored decision. Most // legitimate clients always send this header, so we recommend blocking // requests without it. + // See https://docs.arcjet.com/bot-protection/concepts#user-agent-header this.logger.warn("User-Agent header is missing"); throw new HttpException("Bad request", HttpStatus.BAD_REQUEST); } else { diff --git a/src/content/docs/reference/nodejs.mdx b/src/content/docs/reference/nodejs.mdx index 992e2aef..7c0f5f2f 100644 --- a/src/content/docs/reference/nodejs.mdx +++ b/src/content/docs/reference/nodejs.mdx @@ -436,13 +436,23 @@ If there is an error condition, Arcjet will return an `ERROR` `conclusion`. ```ts if (decision.isErrored()) { - // Fail open by logging the error and continuing - console.warn("Arcjet error", decision.reason.message); - // You could also fail closed here for very sensitive routes - //res.writeHead(503, { "Content-Type": "application/json" }); - //res.end( - // JSON.stringify({ error: "Service Unavailable", reason: decision.reason }), - //); + if (decision.reason.message.includes("requires user-agent header")) { + // Requests without User-Agent headers can not be identified as any + // particular bot and will be marked as an errored decision. Most + // legitimate clients always send this header, so we recommend blocking + // requests without it. + // See https://docs.arcjet.com/bot-protection/concepts#user-agent-header + res.writeHead(400, { "Content-Type": "application/json" }); + res.end(JSON.stringify({ error: "Bad Request", reason: decision.reason })); + } else { + // Fail open by logging the error and continuing + console.warn("Arcjet error", decision.reason.message); + // You could also fail closed here for very sensitive routes + //res.writeHead(503, { "Content-Type": "application/json" }); + //res.end( + // JSON.stringify({ error: "Service Unavailable", reason: decision.reason }), + //); + } } ``` diff --git a/src/content/docs/reference/remix.mdx b/src/content/docs/reference/remix.mdx index bf0b4a6f..dd52f86c 100644 --- a/src/content/docs/reference/remix.mdx +++ b/src/content/docs/reference/remix.mdx @@ -436,10 +436,19 @@ If there is an error condition, Arcjet will return an `ERROR` `conclusion`. ```ts if (decision.isErrored()) { - // Fail open by logging the error and continuing - console.warn("Arcjet error", decision.reason.message); - // You could also fail closed here for very sensitive routes - //throw new Response("Service unavailable", { status: 503 }); + if (decision.reason.message.includes("requires user-agent header")) { + // Requests without User-Agent headers can not be identified as any + // particular bot and will be marked as an errored decision. Most + // legitimate clients always send this header, so we recommend blocking + // requests without it. + // See https://docs.arcjet.com/bot-protection/concepts#user-agent-header + throw new Response("Bad request", { status: 400 }); + } else { + // Fail open by logging the error and continuing + console.warn("Arcjet error", decision.reason.message); + // You could also fail closed here for very sensitive routes + //throw new Response("Service unavailable", { status: 503 }); + } } ``` diff --git a/src/snippets/bot-protection/reference/bun/Errors.js b/src/snippets/bot-protection/reference/bun/Errors.js index ad8a2504..5996ccfe 100644 --- a/src/snippets/bot-protection/reference/bun/Errors.js +++ b/src/snippets/bot-protection/reference/bun/Errors.js @@ -16,15 +16,21 @@ export default { fetch: aj.handler(async (req) => { const decision = await aj.protect(req); - // If the request is missing a User-Agent header, the decision will be - // marked as an error! You should check for this and make a decision about - // the request since requests without a User-Agent could indicate a crafted - // request from an automated client. if (decision.isErrored()) { - // Fail open by logging the error and continuing - console.warn("Arcjet error", decision.reason.message); - // You could also fail closed here if the request is missing a User-Agent - //return new Response("Service unavailable", { status: 503 }); + if (decision.reason.message.includes("requires user-agent header")) { + // Requests without User-Agent headers can not be identified as any + // particular bot and will be marked as an errored decision. Most + // legitimate clients always send this header, so we recommend blocking + // requests without it. + // See https://docs.arcjet.com/bot-protection/concepts#user-agent-header + console.warn("User-Agent header is missing"); + return new Response("Bad request", { status: 400 }); + } else { + // Fail open by logging the error and continuing + console.warn("Arcjet error", decision.reason.message); + // You could also fail closed here for very sensitive routes + //return new Response("Service unavailable", { status: 503 }); + } } if (decision.isDenied()) { diff --git a/src/snippets/bot-protection/reference/bun/Errors.ts b/src/snippets/bot-protection/reference/bun/Errors.ts index d4ac3267..287d3160 100644 --- a/src/snippets/bot-protection/reference/bun/Errors.ts +++ b/src/snippets/bot-protection/reference/bun/Errors.ts @@ -16,15 +16,21 @@ export default { fetch: aj.handler(async (req) => { const decision = await aj.protect(req); - // If the request is missing a User-Agent header, the decision will be - // marked as an error! You should check for this and make a decision about - // the request since requests without a User-Agent could indicate a crafted - // request from an automated client. if (decision.isErrored()) { - // Fail open by logging the error and continuing - console.warn("Arcjet error", decision.reason.message); - // You could also fail closed here if the request is missing a User-Agent - //return new Response("Service unavailable", { status: 503 }); + if (decision.reason.message.includes("requires user-agent header")) { + // Requests without User-Agent headers can not be identified as any + // particular bot and will be marked as an errored decision. Most + // legitimate clients always send this header, so we recommend blocking + // requests without it. + // See https://docs.arcjet.com/bot-protection/concepts#user-agent-header + console.warn("User-Agent header is missing"); + return new Response("Bad request", { status: 400 }); + } else { + // Fail open by logging the error and continuing + console.warn("Arcjet error", decision.reason.message); + // You could also fail closed here for very sensitive routes + //return new Response("Service unavailable", { status: 503 }); + } } if (decision.isDenied()) { diff --git a/src/snippets/bot-protection/reference/deno/Errors.ts b/src/snippets/bot-protection/reference/deno/Errors.ts index c70500da..352bdb7b 100644 --- a/src/snippets/bot-protection/reference/deno/Errors.ts +++ b/src/snippets/bot-protection/reference/deno/Errors.ts @@ -15,15 +15,21 @@ Deno.serve( aj.handler(async (req) => { const decision = await aj.protect(req); - // If the request is missing a User-Agent header, the decision will be - // marked as an error! You should check for this and make a decision about - // the request since requests without a User-Agent could indicate a crafted - // request from an automated client. if (decision.isErrored()) { - // Fail open by logging the error and continuing - console.warn("Arcjet error", decision.reason.message); - // You could also fail closed here if the request is missing a User-Agent - //return new Response("Service unavailable", { status: 503 }); + if (decision.reason.message.includes("requires user-agent header")) { + // Requests without User-Agent headers can not be identified as any + // particular bot and will be marked as an errored decision. Most + // legitimate clients always send this header, so we recommend blocking + // requests without it. + // See https://docs.arcjet.com/bot-protection/concepts#user-agent-header + console.warn("User-Agent header is missing"); + return new Response("Bad request", { status: 400 }); + } else { + // Fail open by logging the error and continuing + console.warn("Arcjet error", decision.reason.message); + // You could also fail closed here for very sensitive routes + //return new Response("Service unavailable", { status: 503 }); + } } if (decision.isDenied()) { diff --git a/src/snippets/bot-protection/reference/nestjs/Errors.ts b/src/snippets/bot-protection/reference/nestjs/Errors.ts index 29a650e3..552f3983 100644 --- a/src/snippets/bot-protection/reference/nestjs/Errors.ts +++ b/src/snippets/bot-protection/reference/nestjs/Errors.ts @@ -60,11 +60,12 @@ export class PageController { throw new HttpException("Forbidden", HttpStatus.FORBIDDEN); } } else if (decision.isErrored()) { - if (decision.reason.message.includes("missing User-Agent header")) { + if (decision.reason.message.includes("requires user-agent header")) { // Requests without User-Agent headers can not be identified as any // particular bot and will be marked as an errored decision. Most // legitimate clients always send this header, so we recommend blocking // requests without it. + // See https://docs.arcjet.com/bot-protection/concepts#user-agent-header this.logger.warn("User-Agent header is missing"); throw new HttpException("Bad request", HttpStatus.BAD_REQUEST); } else { diff --git a/src/snippets/bot-protection/reference/nextjs/ErrorsApp.js b/src/snippets/bot-protection/reference/nextjs/ErrorsApp.js index ebaa1bcd..b1be47d5 100644 --- a/src/snippets/bot-protection/reference/nextjs/ErrorsApp.js +++ b/src/snippets/bot-protection/reference/nextjs/ErrorsApp.js @@ -14,15 +14,21 @@ const aj = arcjet({ export async function GET(req) { const decision = await aj.protect(req); - // If the request is missing a User-Agent header, the decision will be - // marked as an error! You should check for this and make a decision about - // the request since requests without a User-Agent could indicate a crafted - // request from an automated client. if (decision.isErrored()) { - // Fail open by logging the error and continuing - console.warn("Arcjet error", decision.reason.message); - // You could also fail closed here if the request is missing a User-Agent - //return NextResponse.json({ error: "Service unavailable" }, { status: 503 }); + if (decision.reason.message.includes("requires user-agent header")) { + // Requests without User-Agent headers can not be identified as any + // particular bot and will be marked as an errored decision. Most + // legitimate clients always send this header, so we recommend blocking + // requests without it. + // See https://docs.arcjet.com/bot-protection/concepts#user-agent-header + console.warn("User-Agent header is missing"); + return new Response("Bad request", { status: 400 }); + } else { + // Fail open by logging the error and continuing + console.warn("Arcjet error", decision.reason.message); + // You could also fail closed here for very sensitive routes + //return new Response("Service unavailable", { status: 503 }); + } } if (decision.isDenied()) { diff --git a/src/snippets/bot-protection/reference/nextjs/ErrorsApp.ts b/src/snippets/bot-protection/reference/nextjs/ErrorsApp.ts index 895627a0..1ab7d7ee 100644 --- a/src/snippets/bot-protection/reference/nextjs/ErrorsApp.ts +++ b/src/snippets/bot-protection/reference/nextjs/ErrorsApp.ts @@ -14,15 +14,21 @@ const aj = arcjet({ export async function GET(req: Request) { const decision = await aj.protect(req); - // If the request is missing a User-Agent header, the decision will be - // marked as an error! You should check for this and make a decision about - // the request since requests without a User-Agent could indicate a crafted - // request from an automated client. if (decision.isErrored()) { - // Fail open by logging the error and continuing - console.warn("Arcjet error", decision.reason.message); - // You could also fail closed here if the request is missing a User-Agent - //return NextResponse.json({ error: "Service unavailable" }, { status: 503 }); + if (decision.reason.message.includes("requires user-agent header")) { + // Requests without User-Agent headers can not be identified as any + // particular bot and will be marked as an errored decision. Most + // legitimate clients always send this header, so we recommend blocking + // requests without it. + // See https://docs.arcjet.com/bot-protection/concepts#user-agent-header + console.warn("User-Agent header is missing"); + return NextResponse.json({ error: "Bad request" }, { status: 400 }); + } else { + // Fail open by logging the error and continuing + console.warn("Arcjet error", decision.reason.message); + // You could also fail closed here for very sensitive routes + //return NextResponse.json({ error: "Service unavailable" }, { status: 503 }); + } } if (decision.isDenied()) { diff --git a/src/snippets/bot-protection/reference/nextjs/ErrorsPages.js b/src/snippets/bot-protection/reference/nextjs/ErrorsPages.js index adddb277..a9467872 100644 --- a/src/snippets/bot-protection/reference/nextjs/ErrorsPages.js +++ b/src/snippets/bot-protection/reference/nextjs/ErrorsPages.js @@ -13,15 +13,21 @@ const aj = arcjet({ export default async function handler(req, res) { const decision = await aj.protect(req); - // If the request is missing a User-Agent header, the decision will be - // marked as an error! You should check for this and make a decision about - // the request since requests without a User-Agent could indicate a crafted - // request from an automated client. if (decision.isErrored()) { - // Fail open by logging the error and continuing - console.warn("Arcjet error", decision.reason.message); - // You could also fail closed here if the request is missing a User-Agent - //return res.status(503).json({ error: "Service unavailable" }); + if (decision.reason.message.includes("requires user-agent header")) { + // Requests without User-Agent headers can not be identified as any + // particular bot and will be marked as an errored decision. Most + // legitimate clients always send this header, so we recommend blocking + // requests without it. + // See https://docs.arcjet.com/bot-protection/concepts#user-agent-header + console.warn("User-Agent header is missing"); + return res.status(400).json({ error: "Bad request" }); + } else { + // Fail open by logging the error and continuing + console.warn("Arcjet error", decision.reason.message); + // You could also fail closed here for very sensitive routes + //return res.status(503).json({ error: "Service unavailable" }); + } } if (decision.isDenied()) { diff --git a/src/snippets/bot-protection/reference/nextjs/ErrorsPages.ts b/src/snippets/bot-protection/reference/nextjs/ErrorsPages.ts index 2b80ae6d..cffbb21e 100644 --- a/src/snippets/bot-protection/reference/nextjs/ErrorsPages.ts +++ b/src/snippets/bot-protection/reference/nextjs/ErrorsPages.ts @@ -17,15 +17,21 @@ export default async function handler( ) { const decision = await aj.protect(req); - // If the request is missing a User-Agent header, the decision will be - // marked as an error! You should check for this and make a decision about - // the request since requests without a User-Agent could indicate a crafted - // request from an automated client. if (decision.isErrored()) { - // Fail open by logging the error and continuing - console.warn("Arcjet error", decision.reason.message); - // You could also fail closed here if the request is missing a User-Agent - //return res.status(503).json({ error: "Service unavailable" }); + if (decision.reason.message.includes("requires user-agent header")) { + // Requests without User-Agent headers can not be identified as any + // particular bot and will be marked as an errored decision. Most + // legitimate clients always send this header, so we recommend blocking + // requests without it. + // See https://docs.arcjet.com/bot-protection/concepts#user-agent-header + console.warn("User-Agent header is missing"); + return res.status(400).json({ error: "Bad request" }); + } else { + // Fail open by logging the error and continuing + console.warn("Arcjet error", decision.reason.message); + // You could also fail closed here for very sensitive routes + //return res.status(503).json({ error: "Service unavailable" }); + } } if (decision.isDenied()) { diff --git a/src/snippets/bot-protection/reference/nodejs/Errors.js b/src/snippets/bot-protection/reference/nodejs/Errors.js index da4b0002..0036ad96 100644 --- a/src/snippets/bot-protection/reference/nodejs/Errors.js +++ b/src/snippets/bot-protection/reference/nodejs/Errors.js @@ -14,16 +14,23 @@ const aj = arcjet({ const server = http.createServer(async function (req, res) { const decision = await aj.protect(req); - // If the request is missing a User-Agent header, the decision will be - // marked as an error! You should check for this and make a decision about - // the request since requests without a User-Agent could indicate a crafted - // request from an automated client. if (decision.isErrored()) { - // Fail open by logging the error and continuing - console.warn("Arcjet error", decision.reason.message); - // You could also fail closed here if the request is missing a User-Agent - //res.writeHead(503, { "Content-Type": "application/json" }); - //res.end(JSON.stringify({ error: "Service unavailable" })); + if (decision.reason.message.includes("requires user-agent header")) { + // Requests without User-Agent headers can not be identified as any + // particular bot and will be marked as an errored decision. Most + // legitimate clients always send this header, so we recommend blocking + // requests without it. + // See https://docs.arcjet.com/bot-protection/concepts#user-agent-header + console.warn("User-Agent header is missing"); + res.writeHead(400, { "Content-Type": "application/json" }); + res.end(JSON.stringify({ error: "Bad request" })); + } else { + // Fail open by logging the error and continuing + console.warn("Arcjet error", decision.reason.message); + // You could also fail closed here for very sensitive routes + //res.writeHead(503, { "Content-Type": "application/json" }); + //res.end(JSON.stringify({ error: "Service unavailable" })); + } } if (decision.isDenied()) { diff --git a/src/snippets/bot-protection/reference/nodejs/Errors.ts b/src/snippets/bot-protection/reference/nodejs/Errors.ts index c9311524..0b7985fc 100644 --- a/src/snippets/bot-protection/reference/nodejs/Errors.ts +++ b/src/snippets/bot-protection/reference/nodejs/Errors.ts @@ -17,16 +17,23 @@ const server = http.createServer(async function ( ) { const decision = await aj.protect(req); - // If the request is missing a User-Agent header, the decision will be - // marked as an error! You should check for this and make a decision about - // the request since requests without a User-Agent could indicate a crafted - // request from an automated client. if (decision.isErrored()) { - // Fail open by logging the error and continuing - console.warn("Arcjet error", decision.reason.message); - // You could also fail closed here if the request is missing a User-Agent - //res.writeHead(503, { "Content-Type": "application/json" }); - //res.end(JSON.stringify({ error: "Service unavailable" })); + if (decision.reason.message.includes("requires user-agent header")) { + // Requests without User-Agent headers can not be identified as any + // particular bot and will be marked as an errored decision. Most + // legitimate clients always send this header, so we recommend blocking + // requests without it. + // See https://docs.arcjet.com/bot-protection/concepts#user-agent-header + console.warn("User-Agent header is missing"); + res.writeHead(400, { "Content-Type": "application/json" }); + res.end(JSON.stringify({ error: "Bad request" })); + } else { + // Fail open by logging the error and continuing + console.warn("Arcjet error", decision.reason.message); + // You could also fail closed here for very sensitive routes + //res.writeHead(503, { "Content-Type": "application/json" }); + //res.end(JSON.stringify({ error: "Service unavailable" })); + } } if (decision.isDenied()) { diff --git a/src/snippets/bot-protection/reference/remix/Errors.js b/src/snippets/bot-protection/reference/remix/Errors.js index ca6400f1..0cfc35dd 100644 --- a/src/snippets/bot-protection/reference/remix/Errors.js +++ b/src/snippets/bot-protection/reference/remix/Errors.js @@ -13,15 +13,21 @@ const aj = arcjet({ export async function loader(args) { const decision = await aj.protect(args); - // If the request is missing a User-Agent header, the decision will be - // marked as an error! You should check for this and make a decision about - // the request since requests without a User-Agent could indicate a crafted - // request from an automated client. if (decision.isErrored()) { - // Fail open by logging the error and continuing - console.warn("Arcjet error", decision.reason.message); - // You could also fail closed here if the request is missing a User-Agent - //throw new Response("Service unavailable", { status: 503 }); + if (decision.reason.message.includes("requires user-agent header")) { + // Requests without User-Agent headers can not be identified as any + // particular bot and will be marked as an errored decision. Most + // legitimate clients always send this header, so we recommend blocking + // requests without it. + // See https://docs.arcjet.com/bot-protection/concepts#user-agent-header + console.warn("User-Agent header is missing"); + throw new Response("Bad request", { status: 400 }); + } else { + // Fail open by logging the error and continuing + console.warn("Arcjet error", decision.reason.message); + // You could also fail closed here for very sensitive routes + //throw new Response("Service unavailable", { status: 503 }); + } } if (decision.isDenied()) { diff --git a/src/snippets/bot-protection/reference/remix/Errors.ts b/src/snippets/bot-protection/reference/remix/Errors.ts index 60a01a98..c3ff8957 100644 --- a/src/snippets/bot-protection/reference/remix/Errors.ts +++ b/src/snippets/bot-protection/reference/remix/Errors.ts @@ -14,15 +14,21 @@ const aj = arcjet({ export async function loader(args: LoaderFunctionArgs) { const decision = await aj.protect(args); - // If the request is missing a User-Agent header, the decision will be - // marked as an error! You should check for this and make a decision about - // the request since requests without a User-Agent could indicate a crafted - // request from an automated client. if (decision.isErrored()) { - // Fail open by logging the error and continuing - console.warn("Arcjet error", decision.reason.message); - // You could also fail closed here if the request is missing a User-Agent - //throw new Response("Service unavailable", { status: 503 }); + if (decision.reason.message.includes("requires user-agent header")) { + // Requests without User-Agent headers can not be identified as any + // particular bot and will be marked as an errored decision. Most + // legitimate clients always send this header, so we recommend blocking + // requests without it. + // See https://docs.arcjet.com/bot-protection/concepts#user-agent-header + console.warn("User-Agent header is missing"); + throw new Response("Bad request", { status: 400 }); + } else { + // Fail open by logging the error and continuing + console.warn("Arcjet error", decision.reason.message); + // You could also fail closed here for very sensitive routes + //throw new Response("Service unavailable", { status: 503 }); + } } if (decision.isDenied()) { diff --git a/src/snippets/bot-protection/reference/sveltekit/Errors.js b/src/snippets/bot-protection/reference/sveltekit/Errors.js index b76e0b87..7599e858 100644 --- a/src/snippets/bot-protection/reference/sveltekit/Errors.js +++ b/src/snippets/bot-protection/reference/sveltekit/Errors.js @@ -15,15 +15,21 @@ const aj = arcjet({ export async function GET(event) { const decision = await aj.protect(event); - // If the request is missing a User-Agent header, the decision will be - // marked as an error! You should check for this and make a decision about - // the request since requests without a User-Agent could indicate a crafted - // request from an automated client. if (decision.isErrored()) { - // Fail open by logging the error and continuing - console.warn("Arcjet error", decision.reason.message); - // You could also fail closed here if the request is missing a User-Agent - //return error(503, { message: "Service unavailable" }); + if (decision.reason.message.includes("requires user-agent header")) { + // Requests without User-Agent headers can not be identified as any + // particular bot and will be marked as an errored decision. Most + // legitimate clients always send this header, so we recommend blocking + // requests without it. + // See https://docs.arcjet.com/bot-protection/concepts#user-agent-header + console.warn("User-Agent header is missing"); + return error(400, { message: "Bad request" }); + } else { + // Fail open by logging the error and continuing + console.warn("Arcjet error", decision.reason.message); + // You could also fail closed here for very sensitive routes + //return error(503, { message: "Service unavailable" }); + } } if (decision.isDenied()) { diff --git a/src/snippets/bot-protection/reference/sveltekit/Errors.ts b/src/snippets/bot-protection/reference/sveltekit/Errors.ts index ecb46918..f1d0974c 100644 --- a/src/snippets/bot-protection/reference/sveltekit/Errors.ts +++ b/src/snippets/bot-protection/reference/sveltekit/Errors.ts @@ -15,15 +15,21 @@ const aj = arcjet({ export async function GET(event: RequestEvent) { const decision = await aj.protect(event); - // If the request is missing a User-Agent header, the decision will be - // marked as an error! You should check for this and make a decision about - // the request since requests without a User-Agent could indicate a crafted - // request from an automated client. if (decision.isErrored()) { - // Fail open by logging the error and continuing - console.warn("Arcjet error", decision.reason.message); - // You could also fail closed here if the request is missing a User-Agent - //return error(503, { message: "Service unavailable" }); + if (decision.reason.message.includes("requires user-agent header")) { + // Requests without User-Agent headers can not be identified as any + // particular bot and will be marked as an errored decision. Most + // legitimate clients always send this header, so we recommend blocking + // requests without it. + // See https://docs.arcjet.com/bot-protection/concepts#user-agent-header + console.warn("User-Agent header is missing"); + return error(400, { message: "Bad request" }); + } else { + // Fail open by logging the error and continuing + console.warn("Arcjet error", decision.reason.message); + // You could also fail closed here for very sensitive routes + //return error(503, { message: "Service unavailable" }); + } } if (decision.isDenied()) { diff --git a/src/snippets/reference/sveltekit/ErrorHandling.js b/src/snippets/reference/sveltekit/ErrorHandling.js index 15746499..515e337a 100644 --- a/src/snippets/reference/sveltekit/ErrorHandling.js +++ b/src/snippets/reference/sveltekit/ErrorHandling.js @@ -19,11 +19,12 @@ export async function handle({ event, resolve }) { const decision = await aj.protect(event); if (decision.isErrored()) { - if (decision.reason.message.includes("missing User-Agent header")) { + if (decision.reason.message.includes("requires user-agent header")) { // Requests without User-Agent headers can not be identified as any // particular bot and will be marked as an errored decision. Most // legitimate clients always send this header, so we recommend blocking // requests without it. + // See https://docs.arcjet.com/bot-protection/concepts#user-agent-header console.warn("User-Agent header is missing"); return error(400, "Bad request"); } else { diff --git a/src/snippets/reference/sveltekit/ErrorHandling.ts b/src/snippets/reference/sveltekit/ErrorHandling.ts index 52ad2d7b..70fde8a4 100644 --- a/src/snippets/reference/sveltekit/ErrorHandling.ts +++ b/src/snippets/reference/sveltekit/ErrorHandling.ts @@ -25,11 +25,12 @@ export async function handle({ const decision = await aj.protect(event); if (decision.isErrored()) { - if (decision.reason.message.includes("missing User-Agent header")) { + if (decision.reason.message.includes("requires user-agent header")) { // Requests without User-Agent headers can not be identified as any // particular bot and will be marked as an errored decision. Most // legitimate clients always send this header, so we recommend blocking // requests without it. + // See https://docs.arcjet.com/bot-protection/concepts#user-agent-header console.warn("User-Agent header is missing"); return error(400, "Bad request"); } else { diff --git a/src/snippets/shield/reference/nestjs/Errors.ts b/src/snippets/shield/reference/nestjs/Errors.ts index 8ff7c2b2..8954a4ed 100644 --- a/src/snippets/shield/reference/nestjs/Errors.ts +++ b/src/snippets/shield/reference/nestjs/Errors.ts @@ -53,18 +53,9 @@ export class PageController { if (decision.isDenied()) { throw new HttpException("Forbidden", HttpStatus.FORBIDDEN); } else if (decision.isErrored()) { - if (decision.reason.message.includes("missing User-Agent header")) { - // Requests without User-Agent headers can not be identified as any - // particular bot and will be marked as an errored decision. Most - // legitimate clients always send this header, so we recommend blocking - // requests without it. - this.logger.warn("User-Agent header is missing"); - throw new HttpException("Bad request", HttpStatus.BAD_REQUEST); - } else { - // Fail open to prevent an Arcjet error from blocking all requests. You - // may want to fail closed if this controller is very sensitive - this.logger.error(`Arcjet error: ${decision.reason.message}`); - } + // Fail open to prevent an Arcjet error from blocking all requests. You + // may want to fail closed if this controller is very sensitive + this.logger.error(`Arcjet error: ${decision.reason.message}`); } return this.pageService.message(); diff --git a/src/snippets/signup-protection/reference/bun/Errors.js b/src/snippets/signup-protection/reference/bun/Errors.js index d22ca483..85338869 100644 --- a/src/snippets/signup-protection/reference/bun/Errors.js +++ b/src/snippets/signup-protection/reference/bun/Errors.js @@ -41,10 +41,20 @@ export default { console.log("Arcjet decision", decision); if (decision.isErrored()) { - // Fail open by logging the error and continuing - console.warn("Arcjet error", decision.reason.message); - // You could also fail closed here for very sensitive routes - //return new Response("Service unavailable", { status: 503 }); + if (decision.reason.message.includes("requires user-agent header")) { + // Requests without User-Agent headers can not be identified as any + // particular bot and will be marked as an errored decision. Most + // legitimate clients always send this header, so we recommend blocking + // requests without it. + // See https://docs.arcjet.com/bot-protection/concepts#user-agent-header + console.warn("User-Agent header is missing"); + return new Response("Bad request", { status: 400 }); + } else { + // Fail open by logging the error and continuing + console.warn("Arcjet error", decision.reason.message); + // You could also fail closed here for very sensitive routes + //return new Response("Service unavailable", { status: 503 }); + } } if (decision.isDenied()) { diff --git a/src/snippets/signup-protection/reference/bun/Errors.ts b/src/snippets/signup-protection/reference/bun/Errors.ts index d625ca74..e4a91733 100644 --- a/src/snippets/signup-protection/reference/bun/Errors.ts +++ b/src/snippets/signup-protection/reference/bun/Errors.ts @@ -41,10 +41,20 @@ export default { console.log("Arcjet decision", decision); if (decision.isErrored()) { - // Fail open by logging the error and continuing - console.warn("Arcjet error", decision.reason.message); - // You could also fail closed here for very sensitive routes - //return new Response("Service unavailable", { status: 503 }); + if (decision.reason.message.includes("requires user-agent header")) { + // Requests without User-Agent headers can not be identified as any + // particular bot and will be marked as an errored decision. Most + // legitimate clients always send this header, so we recommend blocking + // requests without it. + // See https://docs.arcjet.com/bot-protection/concepts#user-agent-header + console.warn("User-Agent header is missing"); + return new Response("Bad request", { status: 400 }); + } else { + // Fail open by logging the error and continuing + console.warn("Arcjet error", decision.reason.message); + // You could also fail closed here for very sensitive routes + //return new Response("Service unavailable", { status: 503 }); + } } if (decision.isDenied()) { diff --git a/src/snippets/signup-protection/reference/nestjs/Errors.ts b/src/snippets/signup-protection/reference/nestjs/Errors.ts index 45403f60..b9cae711 100644 --- a/src/snippets/signup-protection/reference/nestjs/Errors.ts +++ b/src/snippets/signup-protection/reference/nestjs/Errors.ts @@ -118,11 +118,12 @@ export class SignupController { throw new HttpException("Forbidden", HttpStatus.FORBIDDEN); } } else if (decision.isErrored()) { - if (decision.reason.message.includes("missing User-Agent header")) { + if (decision.reason.message.includes("requires user-agent header")) { // Requests without User-Agent headers can not be identified as any // particular bot and will be marked as an errored decision. Most // legitimate clients always send this header, so we recommend blocking // requests without it. + // See https://docs.arcjet.com/bot-protection/concepts#user-agent-header this.logger.warn("User-Agent header is missing"); throw new HttpException("Bad request", HttpStatus.BAD_REQUEST); } else { diff --git a/src/snippets/signup-protection/reference/nextjs/ErrorHandlingApp.js b/src/snippets/signup-protection/reference/nextjs/ErrorHandlingApp.js index 595c23de..cb05fed0 100644 --- a/src/snippets/signup-protection/reference/nextjs/ErrorHandlingApp.js +++ b/src/snippets/signup-protection/reference/nextjs/ErrorHandlingApp.js @@ -32,10 +32,20 @@ export async function POST(req) { }); if (decision.isErrored()) { - // Fail open by logging the error and continuing - console.warn("Arcjet error", decision.reason.message); - // You could also fail closed here for very sensitive routes - //return NextResponse.json({ error: "Service unavailable" }, { status: 503 }); + if (decision.reason.message.includes("requires user-agent header")) { + // Requests without User-Agent headers can not be identified as any + // particular bot and will be marked as an errored decision. Most + // legitimate clients always send this header, so we recommend blocking + // requests without it. + // See https://docs.arcjet.com/bot-protection/concepts#user-agent-header + console.warn("User-Agent header is missing"); + return NextResponse.json({ error: "Bad request" }, { status: 400 }); + } else { + // Fail open by logging the error and continuing + console.warn("Arcjet error", decision.reason.message); + // You could also fail closed here for very sensitive routes + //return NextResponse.json({ error: "Service unavailable" }, { status: 503 }); + } } if (decision.isDenied()) { diff --git a/src/snippets/signup-protection/reference/nextjs/ErrorHandlingApp.ts b/src/snippets/signup-protection/reference/nextjs/ErrorHandlingApp.ts index db13a1d0..26b6e6fe 100644 --- a/src/snippets/signup-protection/reference/nextjs/ErrorHandlingApp.ts +++ b/src/snippets/signup-protection/reference/nextjs/ErrorHandlingApp.ts @@ -32,10 +32,20 @@ export async function POST(req: Request) { }); if (decision.isErrored()) { - // Fail open by logging the error and continuing - console.warn("Arcjet error", decision.reason.message); - // You could also fail closed here for very sensitive routes - //return NextResponse.json({ error: "Service unavailable" }, { status: 503 }); + if (decision.reason.message.includes("requires user-agent header")) { + // Requests without User-Agent headers can not be identified as any + // particular bot and will be marked as an errored decision. Most + // legitimate clients always send this header, so we recommend blocking + // requests without it. + // See https://docs.arcjet.com/bot-protection/concepts#user-agent-header + console.warn("User-Agent header is missing"); + return NextResponse.json({ error: "Bad request" }, { status: 400 }); + } else { + // Fail open by logging the error and continuing + console.warn("Arcjet error", decision.reason.message); + // You could also fail closed here for very sensitive routes + //return NextResponse.json({ error: "Service unavailable" }, { status: 503 }); + } } if (decision.isDenied()) { diff --git a/src/snippets/signup-protection/reference/nextjs/ErrorHandlingPages.js b/src/snippets/signup-protection/reference/nextjs/ErrorHandlingPages.js index 50533d9a..6bed024d 100644 --- a/src/snippets/signup-protection/reference/nextjs/ErrorHandlingPages.js +++ b/src/snippets/signup-protection/reference/nextjs/ErrorHandlingPages.js @@ -31,10 +31,20 @@ export default async function handler(req, res) { }); if (decision.isErrored()) { - // Fail open by logging the error and continuing - console.warn("Arcjet error", decision.reason.message); - // You could also fail closed here for very sensitive routes - //return res.status(503).json({ error: "Service unavailable" }); + if (decision.reason.message.includes("requires user-agent header")) { + // Requests without User-Agent headers can not be identified as any + // particular bot and will be marked as an errored decision. Most + // legitimate clients always send this header, so we recommend blocking + // requests without it. + // See https://docs.arcjet.com/bot-protection/concepts#user-agent-header + console.warn("User-Agent header is missing"); + return res.status(400).json({ error: "Bad request" }); + } else { + // Fail open by logging the error and continuing + console.warn("Arcjet error", decision.reason.message); + // You could also fail closed here for very sensitive routes + //return res.status(503).json({ error: "Service unavailable" }); + } } if (decision.isDenied()) { diff --git a/src/snippets/signup-protection/reference/nextjs/ErrorHandlingPages.ts b/src/snippets/signup-protection/reference/nextjs/ErrorHandlingPages.ts index ce21af98..049aec6e 100644 --- a/src/snippets/signup-protection/reference/nextjs/ErrorHandlingPages.ts +++ b/src/snippets/signup-protection/reference/nextjs/ErrorHandlingPages.ts @@ -41,6 +41,23 @@ export default async function handler( //return res.status(503).json({ error: "Service unavailable" }); } + if (decision.isErrored()) { + if (decision.reason.message.includes("requires user-agent header")) { + // Requests without User-Agent headers can not be identified as any + // particular bot and will be marked as an errored decision. Most + // legitimate clients always send this header, so we recommend blocking + // requests without it. + // See https://docs.arcjet.com/bot-protection/concepts#user-agent-header + console.warn("User-Agent header is missing"); + return res.status(400).json({ error: "Bad request" }); + } else { + // Fail open by logging the error and continuing + console.warn("Arcjet error", decision.reason.message); + // You could also fail closed here for very sensitive routes + //return res.status(503).json({ error: "Service unavailable" }); + } + } + if (decision.isDenied()) { if (decision.reason.isEmail()) { return res.status(400).json({ diff --git a/src/snippets/signup-protection/reference/nodejs/Errors.js b/src/snippets/signup-protection/reference/nodejs/Errors.js index 2e92cdf3..a47f4088 100644 --- a/src/snippets/signup-protection/reference/nodejs/Errors.js +++ b/src/snippets/signup-protection/reference/nodejs/Errors.js @@ -44,11 +44,22 @@ app.post("/", async (req, res) => { console.log("Arcjet decision", decision); if (decision.isErrored()) { - // Fail open by logging the error and continuing - console.warn("Arcjet error", decision.reason.message); - // You could also fail closed here for very sensitive routes - //res.writeHead(503, { "Content-Type": "application/json" }); - //res.end(JSON.stringify({ error: "Service unavailable" })); + if (decision.reason.message.includes("requires user-agent header")) { + // Requests without User-Agent headers can not be identified as any + // particular bot and will be marked as an errored decision. Most + // legitimate clients always send this header, so we recommend blocking + // requests without it. + // See https://docs.arcjet.com/bot-protection/concepts#user-agent-header + console.warn("User-Agent header is missing"); + res.writeHead(400, { "Content-Type": "application/json" }); + res.end(JSON.stringify({ error: "Bad request" })); + } else { + // Fail open by logging the error and continuing + console.warn("Arcjet error", decision.reason.message); + // You could also fail closed here for very sensitive routes + //res.writeHead(503, { "Content-Type": "application/json" }); + //res.end(JSON.stringify({ error: "Service unavailable" })); + } } if (decision.isDenied()) { diff --git a/src/snippets/signup-protection/reference/nodejs/Errors.ts b/src/snippets/signup-protection/reference/nodejs/Errors.ts index c0284591..0bfa2278 100644 --- a/src/snippets/signup-protection/reference/nodejs/Errors.ts +++ b/src/snippets/signup-protection/reference/nodejs/Errors.ts @@ -44,11 +44,22 @@ app.post("/", async (req, res) => { console.log("Arcjet decision", decision); if (decision.isErrored()) { - // Fail open by logging the error and continuing - console.warn("Arcjet error", decision.reason.message); - // You could also fail closed here for very sensitive routes - //res.writeHead(503, { "Content-Type": "application/json" }); - //res.end(JSON.stringify({ error: "Service unavailable" })); + if (decision.reason.message.includes("requires user-agent header")) { + // Requests without User-Agent headers can not be identified as any + // particular bot and will be marked as an errored decision. Most + // legitimate clients always send this header, so we recommend blocking + // requests without it. + // See https://docs.arcjet.com/bot-protection/concepts#user-agent-header + console.warn("User-Agent header is missing"); + res.writeHead(400, { "Content-Type": "application/json" }); + res.end(JSON.stringify({ error: "Bad request" })); + } else { + // Fail open by logging the error and continuing + console.warn("Arcjet error", decision.reason.message); + // You could also fail closed here for very sensitive routes + //res.writeHead(503, { "Content-Type": "application/json" }); + //res.end(JSON.stringify({ error: "Service unavailable" })); + } } if (decision.isDenied()) { diff --git a/src/snippets/signup-protection/reference/remix/Errors.js b/src/snippets/signup-protection/reference/remix/Errors.js index 2de31854..f13a348a 100644 --- a/src/snippets/signup-protection/reference/remix/Errors.js +++ b/src/snippets/signup-protection/reference/remix/Errors.js @@ -38,11 +38,20 @@ export async function action(args) { console.log("Arcjet decision", decision); if (decision.isErrored()) { - // Fail open by logging the error and continuing - console.warn("Arcjet error", decision.reason.message); - // You could also fail closed here for very sensitive routes - //res.writeHead(503, { "Content-Type": "application/json" }); - //res.end(JSON.stringify({ error: "Service unavailable" })); + if (decision.reason.message.includes("requires user-agent header")) { + // Requests without User-Agent headers can not be identified as any + // particular bot and will be marked as an errored decision. Most + // legitimate clients always send this header, so we recommend blocking + // requests without it. + // See https://docs.arcjet.com/bot-protection/concepts#user-agent-header + console.warn("User-Agent header is missing"); + return Response.json({ error: "Bad request" }, { status: 400 }); + } else { + // Fail open by logging the error and continuing + console.warn("Arcjet error", decision.reason.message); + // You could also fail closed here for very sensitive routes + //return Response.json({ error: "Service unavailable" }, { status: 503 }); + } } if (decision.isDenied()) { diff --git a/src/snippets/signup-protection/reference/remix/Errors.ts b/src/snippets/signup-protection/reference/remix/Errors.ts index e6f144f1..2c3cae97 100644 --- a/src/snippets/signup-protection/reference/remix/Errors.ts +++ b/src/snippets/signup-protection/reference/remix/Errors.ts @@ -39,11 +39,20 @@ export async function action(args: ActionFunctionArgs) { console.log("Arcjet decision", decision); if (decision.isErrored()) { - // Fail open by logging the error and continuing - console.warn("Arcjet error", decision.reason.message); - // You could also fail closed here for very sensitive routes - //res.writeHead(503, { "Content-Type": "application/json" }); - //res.end(JSON.stringify({ error: "Service unavailable" })); + if (decision.reason.message.includes("requires user-agent header")) { + // Requests without User-Agent headers can not be identified as any + // particular bot and will be marked as an errored decision. Most + // legitimate clients always send this header, so we recommend blocking + // requests without it. + // See https://docs.arcjet.com/bot-protection/concepts#user-agent-header + console.warn("User-Agent header is missing"); + return Response.json({ error: "Bad request" }, { status: 400 }); + } else { + // Fail open by logging the error and continuing + console.warn("Arcjet error", decision.reason.message); + // You could also fail closed here for very sensitive routes + //return Response.json({ error: "Service unavailable" }, { status: 503 }); + } } if (decision.isDenied()) { diff --git a/src/snippets/signup-protection/reference/sveltekit/Errors.js b/src/snippets/signup-protection/reference/sveltekit/Errors.js index a99bfd07..c72637e8 100644 --- a/src/snippets/signup-protection/reference/sveltekit/Errors.js +++ b/src/snippets/signup-protection/reference/sveltekit/Errors.js @@ -40,10 +40,20 @@ export async function POST(event) { }); if (decision.isErrored()) { - // Fail open by logging the error and continuing - console.warn("Arcjet error", decision.reason.message); - // You could also fail closed here for very sensitive routes - //return error(503, { message: "Service unavailable" }); + if (decision.reason.message.includes("requires user-agent header")) { + // Requests without User-Agent headers can not be identified as any + // particular bot and will be marked as an errored decision. Most + // legitimate clients always send this header, so we recommend blocking + // requests without it. + // See https://docs.arcjet.com/bot-protection/concepts#user-agent-header + console.warn("User-Agent header is missing"); + return error(400, { message: "Bad request" }); + } else { + // Fail open by logging the error and continuing + console.warn("Arcjet error", decision.reason.message); + // You could also fail closed here for very sensitive routes + //return error(503, { message: "Service unavailable" }); + } } if (decision.isDenied()) { diff --git a/src/snippets/signup-protection/reference/sveltekit/Errors.ts b/src/snippets/signup-protection/reference/sveltekit/Errors.ts index ea4196ac..b94eb81c 100644 --- a/src/snippets/signup-protection/reference/sveltekit/Errors.ts +++ b/src/snippets/signup-protection/reference/sveltekit/Errors.ts @@ -40,10 +40,20 @@ export async function POST(event: RequestEvent) { }); if (decision.isErrored()) { - // Fail open by logging the error and continuing - console.warn("Arcjet error", decision.reason.message); - // You could also fail closed here for very sensitive routes - //return error(503, { message: "Service unavailable" }); + if (decision.reason.message.includes("requires user-agent header")) { + // Requests without User-Agent headers can not be identified as any + // particular bot and will be marked as an errored decision. Most + // legitimate clients always send this header, so we recommend blocking + // requests without it. + // See https://docs.arcjet.com/bot-protection/concepts#user-agent-header + console.warn("User-Agent header is missing"); + return error(400, { message: "Bad request" }); + } else { + // Fail open by logging the error and continuing + console.warn("Arcjet error", decision.reason.message); + // You could also fail closed here for very sensitive routes + //return error(503, { message: "Service unavailable" }); + } } if (decision.isDenied()) {