Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add isRedirect to context #13143

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

blaine-arcjet
Copy link

Changes

I added the isRedirect field to the Render context. This can help users avoid running middleware on routes that might just be a redirect.

For example, the Arcjet integration fails if run on a redirect because isPrerendered is false, but clientAddress throws if accessed; however, it would be generally recommended not to run Arcjet on a redirect because it'll run on the final endpoint. With this change, we can recommend users skip Arcjet when isRedirect is true.

Testing

I added a test to the redirects fixture that checks a header that is set by the middleware.

Docs

Yep! I'll add this to the Astro docs for Render context if this is something y'all want to include. 🎉

/cc @withastro/maintainers-docs for feedback!

Copy link

changeset-bot bot commented Feb 6, 2025

🦋 Changeset detected

Latest commit: daae1fe

The changes in this PR will be included in the next version bump.

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions github-actions bot added pkg: astro Related to the core `astro` package (scope) docs pr labels Feb 6, 2025
@github-actions github-actions bot added the semver: minor Change triggers a `minor` release label Feb 6, 2025
Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR is blocked because it contains a minor changeset. A reviewer will merge this at the next release if approved.

Copy link

codspeed-hq bot commented Feb 6, 2025

CodSpeed Performance Report

Merging #13143 will not alter performance

Comparing blaine-arcjet:phated/is-redirect (daae1fe) with main (d1384b8)

Summary

✅ 6 untouched benchmarks

@ematipico
Copy link
Member

Unfortunately, it seems that the discussion in the linked issue has a lot of known knowledge, so I miss some context.

Before adding new runtime APIs, we usually want to make sure they are needed. Can you please do a TLDR of why you need it?

Also, can't do something like the following snippet

const response = await next();
if (response.status >= 300 && response.status < 400) {}

@blaine-arcjet
Copy link
Author

Unfortunately, it seems that the discussion in the linked issue has a lot of known knowledge, so I miss some context.

Before adding new runtime APIs, we usually want to make sure they are needed. Can you please do a TLDR of why you need it?

To sum up my discovery process, the fundamental issue is that isPrerendered can be false but accessing clientAddress can still throw. Currently, the only way users can workaround this is by using a try/catch.

I think there needs to be some flag (or combination of flags) on the runtime API that indicates if clientAddress is safe to use. Instead of trying to rework isPrerendered to achieve this, I added isRedirect—I believe users would be able to check if (!isPrerendered && !isRedirect) before accessing clientAddress to ensure it never throws.

I'm open to alternatives to isRedirect if you have a better idea to indicate clientAddress is safe to use.

Also, can't do something like the following snippet

I thought about this, but Arcjet is a unique case here. It is a library for request protection (such as running a WAF, validating emails, detecting bots), so you wouldn't want to run every request through the middleware before protecting, since that would execute each other middleware before users would have a chance to validate the request.

The current recommendation is to not run Arcjet protections on prerendered routes because they are just static files, so we recommend using a middleware like:

import { defineMiddleware } from "astro:middleware";
import aj from "arcjet:client";

export const onRequest = defineMiddleware(async (ctx, next) => {
  if (!ctx.isPrerendered) {
    const decision = await aj.protect(ctx.request);

    if (decision.isDenied()) {
      return new Response(null, { status: 403, statusText: "Forbidden" });
    }
  }

  return next();
});

We additionally don't need to run the protections on redirects, since the redirect should point to either a static page where no protections will need to be run or a dynamic page where the protections will be run.

With the isRedirect runtime API, the above example could be modified:

import { defineMiddleware } from "astro:middleware";
import aj from "arcjet:client";

export const onRequest = defineMiddleware(async (ctx, next) => {
  if (!ctx.isPrerendered && !ctx.isRedirect) {
    const decision = await aj.protect(ctx.request);

    if (decision.isDenied()) {
      return new Response(null, { status: 403, statusText: "Forbidden" });
    }
  }

  return next();
});

But as I said above, I would be happy with any API that indicated if clientAddress is accessible (thus indicating a request came from a client and is not happening during build).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
docs pr pkg: astro Related to the core `astro` package (scope) semver: minor Change triggers a `minor` release
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants