├── basic-auth
├── src
│ ├── env.d.ts
│ ├── pages
│ │ └── index.astro
│ └── middleware.ts
├── tsconfig.json
├── astro.config.mjs
├── package.json
├── public
│ └── favicon.svg
└── README.md
├── hello-world
├── src
│ ├── env.d.ts
│ ├── middleware.ts
│ └── pages
│ │ └── index.astro
├── tsconfig.json
├── astro.config.mjs
├── package.json
├── public
│ └── favicon.svg
└── README.md
├── jwt-auth
├── src
│ ├── env.d.ts
│ ├── constant.ts
│ ├── pages
│ │ ├── api
│ │ │ ├── protected.ts
│ │ │ ├── logout.ts
│ │ │ └── login.ts
│ │ ├── protected.astro
│ │ └── index.astro
│ ├── layouts
│ │ └── Layout.astro
│ └── middleware.ts
├── tsconfig.json
├── astro.config.mjs
├── package.json
├── public
│ └── favicon.svg
└── README.md
├── redirect
├── src
│ ├── env.d.ts
│ ├── middleware.ts
│ ├── layouts
│ │ └── Layout.astro
│ └── pages
│ │ ├── redirected.astro
│ │ └── index.astro
├── tsconfig.json
├── astro.config.mjs
├── .gitignore
├── package.json
├── public
│ └── favicon.svg
└── README.md
├── feature-flag-posthog
├── src
│ ├── env.d.ts
│ ├── layouts
│ │ └── Layout.astro
│ ├── components
│ │ └── Card.astro
│ ├── middleware.ts
│ └── pages
│ │ ├── post-hog.astro
│ │ └── index.astro
├── tsconfig.json
├── astro.config.mjs
├── .gitignore
├── package.json
├── public
│ └── favicon.svg
└── README.md
├── locals-object
├── tsconfig.json
├── astro.config.mjs
├── src
│ ├── env.d.ts
│ ├── middleware.ts
│ ├── layouts
│ │ └── Layout.astro
│ └── pages
│ │ └── index.astro
├── .gitignore
├── package.json
├── public
│ └── favicon.svg
└── README.md
├── multiple-middleware
├── src
│ ├── env.d.ts
│ ├── middleware
│ │ ├── auth.ts
│ │ ├── index.ts
│ │ └── validate.ts
│ ├── layouts
│ │ └── Layout.astro
│ └── pages
│ │ └── index.astro
├── tsconfig.json
├── astro.config.mjs
├── .gitignore
├── package.json
├── public
│ └── favicon.svg
└── README.md
├── .gitignore
└── README.md
/basic-auth/src/env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/hello-world/src/env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/jwt-auth/src/env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/redirect/src/env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/jwt-auth/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "astro/tsconfigs/strict"
3 | }
--------------------------------------------------------------------------------
/basic-auth/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "astro/tsconfigs/strictest"
3 | }
--------------------------------------------------------------------------------
/feature-flag-posthog/src/env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/hello-world/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "astro/tsconfigs/strict"
3 | }
--------------------------------------------------------------------------------
/locals-object/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "astro/tsconfigs/strict"
3 | }
--------------------------------------------------------------------------------
/multiple-middleware/src/env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/redirect/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "astro/tsconfigs/strictest"
3 | }
--------------------------------------------------------------------------------
/feature-flag-posthog/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "astro/tsconfigs/strict"
3 | }
--------------------------------------------------------------------------------
/multiple-middleware/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "astro/tsconfigs/strict"
3 | }
--------------------------------------------------------------------------------
/jwt-auth/src/constant.ts:
--------------------------------------------------------------------------------
1 | export const TOKEN = "token";
2 | export const PUBLIC_ROUTES = ["/", "/api/login", "/api/logout"];
3 |
--------------------------------------------------------------------------------
/hello-world/astro.config.mjs:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'astro/config';
2 |
3 | // https://astro.build/config
4 | export default defineConfig({});
5 |
--------------------------------------------------------------------------------
/redirect/astro.config.mjs:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'astro/config';
2 |
3 | // https://astro.build/config
4 | export default defineConfig({});
5 |
--------------------------------------------------------------------------------
/locals-object/astro.config.mjs:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'astro/config';
2 |
3 | // https://astro.build/config
4 | export default defineConfig({});
5 |
--------------------------------------------------------------------------------
/feature-flag-posthog/astro.config.mjs:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'astro/config';
2 |
3 | // https://astro.build/config
4 | export default defineConfig({});
5 |
--------------------------------------------------------------------------------
/multiple-middleware/astro.config.mjs:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'astro/config';
2 |
3 | // https://astro.build/config
4 | export default defineConfig({});
5 |
--------------------------------------------------------------------------------
/basic-auth/astro.config.mjs:
--------------------------------------------------------------------------------
1 | import { defineConfig } from "astro/config";
2 |
3 | // https://astro.build/config
4 | export default defineConfig({
5 | output: "server",
6 | });
7 |
--------------------------------------------------------------------------------
/locals-object/src/env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | declare namespace App {
3 | interface Locals {
4 | stringValue: string;
5 | functionValue: () => string;
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/multiple-middleware/src/middleware/auth.ts:
--------------------------------------------------------------------------------
1 | import { defineMiddleware } from "astro/middleware";
2 |
3 | export const auth = defineMiddleware((context, next) => {
4 | console.log("In auth middleware");
5 | return next();
6 | });
7 |
--------------------------------------------------------------------------------
/multiple-middleware/src/middleware/index.ts:
--------------------------------------------------------------------------------
1 | import { sequence } from "astro/middleware";
2 |
3 | import { auth } from "./auth";
4 | import { validate } from "./validate";
5 |
6 | export const onRequest = sequence(auth, validate);
7 |
--------------------------------------------------------------------------------
/multiple-middleware/src/middleware/validate.ts:
--------------------------------------------------------------------------------
1 | import { defineMiddleware } from "astro/middleware";
2 |
3 | export const validate = defineMiddleware((context, next) => {
4 | console.log("In validate middleware");
5 | return next();
6 | });
7 |
--------------------------------------------------------------------------------
/jwt-auth/astro.config.mjs:
--------------------------------------------------------------------------------
1 | import { defineConfig } from "astro/config";
2 |
3 | import netlify from "@astrojs/netlify/functions";
4 |
5 | // https://astro.build/config
6 | export default defineConfig({
7 | output: "server",
8 | adapter: netlify()
9 | });
--------------------------------------------------------------------------------
/jwt-auth/src/pages/api/protected.ts:
--------------------------------------------------------------------------------
1 | import type { APIRoute } from "astro";
2 |
3 | export const get: APIRoute = (ctx) => {
4 | return new Response(
5 | JSON.stringify({
6 | message: "You're logged in!",
7 | }),
8 | { status: 200 }
9 | );
10 | };
11 |
--------------------------------------------------------------------------------
/redirect/.gitignore:
--------------------------------------------------------------------------------
1 | # build output
2 | dist/
3 |
4 | # generated types
5 | .astro/
6 |
7 | # dependencies
8 | node_modules/
9 |
10 | # logs
11 | npm-debug.log*
12 | yarn-debug.log*
13 | yarn-error.log*
14 | pnpm-debug.log*
15 |
16 | # environment variables
17 | .env
18 | .env.production
19 |
20 | # macOS-specific files
21 | .DS_Store
22 |
--------------------------------------------------------------------------------
/redirect/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "redirect",
3 | "type": "module",
4 | "version": "0.0.1",
5 | "scripts": {
6 | "dev": "astro dev",
7 | "start": "astro dev",
8 | "build": "astro build",
9 | "preview": "astro preview",
10 | "astro": "astro"
11 | },
12 | "dependencies": {
13 | "astro": "^2.10.14"
14 | }
15 | }
--------------------------------------------------------------------------------
/locals-object/.gitignore:
--------------------------------------------------------------------------------
1 | # build output
2 | dist/
3 |
4 | # generated types
5 | .astro/
6 |
7 | # dependencies
8 | node_modules/
9 |
10 | # logs
11 | npm-debug.log*
12 | yarn-debug.log*
13 | yarn-error.log*
14 | pnpm-debug.log*
15 |
16 | # environment variables
17 | .env
18 | .env.production
19 |
20 | # macOS-specific files
21 | .DS_Store
22 |
--------------------------------------------------------------------------------
/feature-flag-posthog/.gitignore:
--------------------------------------------------------------------------------
1 | # build output
2 | dist/
3 |
4 | # generated types
5 | .astro/
6 |
7 | # dependencies
8 | node_modules/
9 |
10 | # logs
11 | npm-debug.log*
12 | yarn-debug.log*
13 | yarn-error.log*
14 | pnpm-debug.log*
15 |
16 | # environment variables
17 | .env
18 | .env.production
19 |
20 | # macOS-specific files
21 | .DS_Store
22 |
--------------------------------------------------------------------------------
/hello-world/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hello-world",
3 | "type": "module",
4 | "version": "0.0.1",
5 | "scripts": {
6 | "dev": "astro dev",
7 | "start": "astro dev",
8 | "build": "astro build",
9 | "preview": "astro preview",
10 | "astro": "astro"
11 | },
12 | "dependencies": {
13 | "astro": "^2.10.14"
14 | }
15 | }
--------------------------------------------------------------------------------
/locals-object/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "locals-object",
3 | "type": "module",
4 | "version": "0.0.1",
5 | "scripts": {
6 | "dev": "astro dev",
7 | "start": "astro dev",
8 | "build": "astro build",
9 | "preview": "astro preview",
10 | "astro": "astro"
11 | },
12 | "dependencies": {
13 | "astro": "^2.10.14"
14 | }
15 | }
--------------------------------------------------------------------------------
/multiple-middleware/.gitignore:
--------------------------------------------------------------------------------
1 | # build output
2 | dist/
3 |
4 | # generated types
5 | .astro/
6 |
7 | # dependencies
8 | node_modules/
9 |
10 | # logs
11 | npm-debug.log*
12 | yarn-debug.log*
13 | yarn-error.log*
14 | pnpm-debug.log*
15 |
16 | # environment variables
17 | .env
18 | .env.production
19 |
20 | # macOS-specific files
21 | .DS_Store
22 |
--------------------------------------------------------------------------------
/hello-world/src/middleware.ts:
--------------------------------------------------------------------------------
1 | import { defineMiddleware } from "astro/middleware";
2 |
3 | export const onRequest = defineMiddleware((context, next) => {
4 | console.log("MIDDLEWARE");
5 |
6 | return new Response(
7 | JSON.stringify({
8 | message: "Hello world",
9 | }),
10 | {
11 | status: 200,
12 | }
13 | );
14 | });
15 |
--------------------------------------------------------------------------------
/multiple-middleware/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "multiple-middleware",
3 | "type": "module",
4 | "version": "0.0.1",
5 | "scripts": {
6 | "dev": "astro dev",
7 | "start": "astro dev",
8 | "build": "astro build",
9 | "preview": "astro preview",
10 | "astro": "astro"
11 | },
12 | "dependencies": {
13 | "astro": "^2.10.14"
14 | }
15 | }
--------------------------------------------------------------------------------
/basic-auth/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "astro-middleware-examples-basic-auth",
3 | "type": "module",
4 | "version": "0.0.1",
5 | "scripts": {
6 | "dev": "astro dev",
7 | "start": "astro dev",
8 | "build": "astro build",
9 | "preview": "astro preview",
10 | "astro": "astro"
11 | },
12 | "dependencies": {
13 | "astro": "^2.10.7"
14 | }
15 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # build output
2 | dist/
3 | .netlify/
4 |
5 | # generated types
6 | .astro/
7 |
8 | # dependencies
9 | node_modules/
10 |
11 | # logs
12 | npm-debug.log*
13 | yarn-debug.log*
14 | yarn-error.log*
15 | pnpm-debug.log*
16 |
17 | # environment variables
18 | .env
19 | .env.production
20 |
21 | # macOS-specific files
22 | .DS_Store
23 |
24 | # code editor(s)
25 | .vscode/
--------------------------------------------------------------------------------
/basic-auth/src/pages/index.astro:
--------------------------------------------------------------------------------
1 | ---
2 | ---
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | Astro
11 |
12 |
13 | Astro
14 |
15 |
16 |
--------------------------------------------------------------------------------
/locals-object/src/middleware.ts:
--------------------------------------------------------------------------------
1 | import { defineMiddleware } from "astro/middleware";
2 |
3 | export const onRequest = defineMiddleware((context, next) => {
4 | // add a string value to the locals object
5 | context.locals.stringValue = "Hello Middleware";
6 |
7 | // add a method to the locals object
8 | context.locals.functionValue = () => "This is a function return value";
9 |
10 | return next();
11 | });
12 |
--------------------------------------------------------------------------------
/jwt-auth/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jwt-auth",
3 | "type": "module",
4 | "version": "0.0.1",
5 | "scripts": {
6 | "dev": "astro dev",
7 | "start": "astro dev",
8 | "build": "astro build",
9 | "preview": "astro preview",
10 | "astro": "astro"
11 | },
12 | "dependencies": {
13 | "@astrojs/netlify": "^2.6.0",
14 | "astro": "^2.10.9",
15 | "jose": "^4.14.4",
16 | "nanoid": "^4.0.2"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/hello-world/src/pages/index.astro:
--------------------------------------------------------------------------------
1 | ---
2 | console.log("Rendering the index page");
3 | ---
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | Astro
12 |
13 |
14 | Astro
15 |
16 |
17 |
--------------------------------------------------------------------------------
/feature-flag-posthog/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "--template-basic",
3 | "type": "module",
4 | "version": "0.0.1",
5 | "scripts": {
6 | "dev": "astro dev",
7 | "start": "astro dev",
8 | "build": "astro build",
9 | "preview": "astro preview",
10 | "astro": "astro"
11 | },
12 | "dependencies": {
13 | "@growthbook/growthbook": "^0.28.0",
14 | "astro": "^3.0.12",
15 | "eventsource": "^2.0.2",
16 | "posthog-node": "^3.1.2"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/jwt-auth/src/pages/api/logout.ts:
--------------------------------------------------------------------------------
1 | import type { APIRoute } from "astro";
2 | import { TOKEN } from "../../constant";
3 |
4 | export const post: APIRoute = async (ctx) => {
5 | try {
6 | // unset cookies
7 | ctx.cookies.set(TOKEN, "", {
8 | httpOnly: true,
9 | maxAge: 0,
10 | path: "/",
11 | });
12 |
13 | return new Response(
14 | JSON.stringify({
15 | message: "You're logged out!",
16 | }),
17 | {
18 | status: 200,
19 | }
20 | );
21 | } catch (error) {
22 | console.debug(error);
23 |
24 | return new Response(
25 | JSON.stringify({
26 | message: "Logout failed",
27 | }),
28 | {
29 | status: 500,
30 | }
31 | );
32 | }
33 | };
34 |
--------------------------------------------------------------------------------
/jwt-auth/public/favicon.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
--------------------------------------------------------------------------------
/redirect/public/favicon.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
--------------------------------------------------------------------------------
/basic-auth/public/favicon.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
--------------------------------------------------------------------------------
/hello-world/public/favicon.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
--------------------------------------------------------------------------------
/locals-object/public/favicon.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
--------------------------------------------------------------------------------
/multiple-middleware/public/favicon.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
--------------------------------------------------------------------------------
/feature-flag-posthog/public/favicon.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
--------------------------------------------------------------------------------
/redirect/src/middleware.ts:
--------------------------------------------------------------------------------
1 | import { defineMiddleware } from "astro/middleware";
2 |
3 | const INDEX_PATH = "/";
4 |
5 | export const onRequest = defineMiddleware((context, next) => {
6 | /**
7 | * The middleware runs every time a page or endpoint is about to be rendered.
8 | * Only redirect if this is the home page
9 | */
10 | if (context.url.pathname === INDEX_PATH) {
11 | return Response.redirect(new URL("/redirected", context.url), 302);
12 |
13 | /**
14 | * You may also redirect using `context.redirect` as shown below:
15 | * =========================================
16 | * context.redirect("/redirected", 302);
17 | * =========================================
18 | * Note that this only works in SSR mode
19 | */
20 | }
21 |
22 | return next();
23 | });
24 |
--------------------------------------------------------------------------------
/jwt-auth/README.md:
--------------------------------------------------------------------------------
1 | # Astro JWT Middleware
2 |
3 | 
4 |
5 | ## 🧞 Commands
6 |
7 | All commands are run from the root of the project, from a terminal:
8 |
9 | | Command | Action |
10 | | :------------------------ | :----------------------------------------------- |
11 | | `npm install` | Installs dependencies |
12 | | `npm run dev` | Starts local dev server at `localhost:3000` |
13 | | `npm run build` | Build your production site to `./dist/` |
14 | | `npm run preview` | Preview your build locally, before deploying |
15 | | `npm run astro ...` | Run CLI commands like `astro add`, `astro check` |
16 | | `npm run astro -- --help` | Get help using the Astro CLI |
17 |
--------------------------------------------------------------------------------
/locals-object/README.md:
--------------------------------------------------------------------------------
1 | # Astro Locals Object
2 |
3 | 
4 |
5 | ## 🧞 Commands
6 |
7 | All commands are run from the root of the project, from a terminal:
8 |
9 | | Command | Action |
10 | | :------------------------ | :----------------------------------------------- |
11 | | `npm install` | Installs dependencies |
12 | | `npm run dev` | Starts local dev server at `localhost:3000` |
13 | | `npm run build` | Build your production site to `./dist/` |
14 | | `npm run preview` | Preview your build locally, before deploying |
15 | | `npm run astro ...` | Run CLI commands like `astro add`, `astro check` |
16 | | `npm run astro -- --help` | Get help using the Astro CLI |
17 |
--------------------------------------------------------------------------------
/redirect/README.md:
--------------------------------------------------------------------------------
1 | # Astro Redirect Middleware
2 |
3 | 
4 |
5 | ## 🧞 Commands
6 |
7 | All commands are run from the root of the project, from a terminal:
8 |
9 | | Command | Action |
10 | | :------------------------ | :----------------------------------------------- |
11 | | `npm install` | Installs dependencies |
12 | | `npm run dev` | Starts local dev server at `localhost:3000` |
13 | | `npm run build` | Build your production site to `./dist/` |
14 | | `npm run preview` | Preview your build locally, before deploying |
15 | | `npm run astro ...` | Run CLI commands like `astro add`, `astro check` |
16 | | `npm run astro -- --help` | Get help using the Astro CLI |
17 |
--------------------------------------------------------------------------------
/basic-auth/README.md:
--------------------------------------------------------------------------------
1 | # Astro Basic auth Middleware
2 |
3 | 
4 |
5 | ## 🧞 Commands
6 |
7 | All commands are run from the root of the project, from a terminal:
8 |
9 | | Command | Action |
10 | | :------------------------ | :----------------------------------------------- |
11 | | `npm install` | Installs dependencies |
12 | | `npm run dev` | Starts local dev server at `localhost:3000` |
13 | | `npm run build` | Build your production site to `./dist/` |
14 | | `npm run preview` | Preview your build locally, before deploying |
15 | | `npm run astro ...` | Run CLI commands like `astro add`, `astro check` |
16 | | `npm run astro -- --help` | Get help using the Astro CLI |
17 |
--------------------------------------------------------------------------------
/hello-world/README.md:
--------------------------------------------------------------------------------
1 | # Astro Hello World Middleware
2 |
3 | 
4 |
5 | ## 🧞 Commands
6 |
7 | All commands are run from the root of the project, from a terminal:
8 |
9 | | Command | Action |
10 | | :------------------------ | :----------------------------------------------- |
11 | | `npm install` | Installs dependencies |
12 | | `npm run dev` | Starts local dev server at `localhost:3000` |
13 | | `npm run build` | Build your production site to `./dist/` |
14 | | `npm run preview` | Preview your build locally, before deploying |
15 | | `npm run astro ...` | Run CLI commands like `astro add`, `astro check` |
16 | | `npm run astro -- --help` | Get help using the Astro CLI |
17 |
--------------------------------------------------------------------------------
/multiple-middleware/README.md:
--------------------------------------------------------------------------------
1 | # Astro Multiple Middleware
2 |
3 | 
4 |
5 | ## 🧞 Commands
6 |
7 | All commands are run from the root of the project, from a terminal:
8 |
9 | | Command | Action |
10 | | :------------------------ | :----------------------------------------------- |
11 | | `npm install` | Installs dependencies |
12 | | `npm run dev` | Starts local dev server at `localhost:3000` |
13 | | `npm run build` | Build your production site to `./dist/` |
14 | | `npm run preview` | Preview your build locally, before deploying |
15 | | `npm run astro ...` | Run CLI commands like `astro add`, `astro check` |
16 | | `npm run astro -- --help` | Get help using the Astro CLI |
17 |
--------------------------------------------------------------------------------
/basic-auth/src/middleware.ts:
--------------------------------------------------------------------------------
1 | import { defineMiddleware } from "astro/middleware";
2 |
3 | export const onRequest = defineMiddleware((context, next) => {
4 | // If a basic auth header is present, it wil take the string form: "Basic authValue"
5 | const basicAuth = context.request.headers.get("authorization");
6 |
7 | if (basicAuth) {
8 | // Get the auth value from string "Basic authValue"
9 | const authValue = basicAuth.split(" ")[1] ?? "username:password";
10 |
11 | // Decode the Base64 encoded string via atob (https://developer.mozilla.org/en-US/docs/Web/API/atob)
12 | // Get the username and password. NB: the decoded string is in the form "username:password"
13 | const [username, pwd] = atob(authValue).split(":");
14 |
15 | // check if the username and password are valid
16 | if (username === "admin" && pwd === "admin") {
17 | // forward request
18 | return next();
19 | }
20 | }
21 |
22 | return new Response("Auth required", {
23 | status: 401,
24 | headers: {
25 | "WWW-authenticate": 'Basic realm="Secure Area"',
26 | },
27 | });
28 | });
29 |
--------------------------------------------------------------------------------
/redirect/src/layouts/Layout.astro:
--------------------------------------------------------------------------------
1 | ---
2 | interface Props {
3 | title: string;
4 | }
5 |
6 | const { title } = Astro.props;
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | {title}
18 |
19 |
20 |
21 |
22 |
23 |
40 |
--------------------------------------------------------------------------------
/locals-object/src/layouts/Layout.astro:
--------------------------------------------------------------------------------
1 | ---
2 | interface Props {
3 | title: string;
4 | }
5 |
6 | const { title } = Astro.props;
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | {title}
18 |
19 |
20 |
21 |
22 |
23 |
40 |
--------------------------------------------------------------------------------
/multiple-middleware/src/layouts/Layout.astro:
--------------------------------------------------------------------------------
1 | ---
2 | interface Props {
3 | title: string;
4 | }
5 |
6 | const { title } = Astro.props;
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | {title}
18 |
19 |
20 |
21 |
22 |
23 |
40 |
--------------------------------------------------------------------------------
/jwt-auth/src/pages/api/login.ts:
--------------------------------------------------------------------------------
1 | import { nanoid } from "nanoid";
2 | import { SignJWT } from "jose";
3 | import type { APIRoute } from "astro";
4 | import { TOKEN } from "../../constant";
5 |
6 | const secret = new TextEncoder().encode(import.meta.env.JWT_SECRET_KEY);
7 |
8 | export const post: APIRoute = async (ctx) => {
9 | try {
10 | const token = await new SignJWT({})
11 | .setProtectedHeader({ alg: "HS256" })
12 | .setJti(nanoid())
13 | .setIssuedAt()
14 | .setExpirationTime("2h")
15 | .sign(secret);
16 |
17 | // set cookies
18 | ctx.cookies.set(TOKEN, token, {
19 | httpOnly: true,
20 | path: "/",
21 | maxAge: 60 * 60 * 2, // 2 hours in seconds
22 | });
23 |
24 | return new Response(
25 | JSON.stringify({
26 | message: "You're logged in!",
27 | }),
28 | {
29 | status: 200,
30 | }
31 | );
32 | } catch (error) {
33 | console.debug(error);
34 |
35 | return new Response(
36 | JSON.stringify({
37 | message: "Login failed",
38 | }),
39 | {
40 | status: 500,
41 | }
42 | );
43 | }
44 | };
45 |
--------------------------------------------------------------------------------
/jwt-auth/src/layouts/Layout.astro:
--------------------------------------------------------------------------------
1 | ---
2 | interface Props {
3 | title: string;
4 | }
5 |
6 | const { title } = Astro.props;
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | {title}
18 |
19 |
20 |
21 |
22 |
23 |
45 |
--------------------------------------------------------------------------------
/feature-flag-posthog/src/layouts/Layout.astro:
--------------------------------------------------------------------------------
1 | ---
2 | interface Props {
3 | title: string;
4 | }
5 |
6 | const { title } = Astro.props;
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | {title}
18 |
19 |
20 |
21 |
22 |
23 |
52 |
--------------------------------------------------------------------------------
/feature-flag-posthog/src/components/Card.astro:
--------------------------------------------------------------------------------
1 | ---
2 | interface Props {
3 | title: string;
4 | body: string;
5 | href: string;
6 | }
7 |
8 | const { href, title, body } = Astro.props;
9 | ---
10 |
11 |
12 |
13 |
14 | {title}
15 | →
16 |
17 |
18 | {body}
19 |
20 |
21 |
22 |
62 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | # Astro Middleware Examples
4 |
5 | - [Hello world](https://github.com/understanding-astro/astro-middleware-examples/tree/master/hello-world)
6 | - [Locals object](https://github.com/understanding-astro/astro-middleware-examples/tree/master/locals-object)
7 | - [Basic Auth](https://github.com/understanding-astro/astro-middleware-examples/tree/master/basic-auth)
8 | - [JWT Auth](https://github.com/understanding-astro/astro-middleware-examples/tree/master/jwt-auth)
9 | - [Redirects](https://github.com/understanding-astro/astro-middleware-examples/tree/master/redirect)
10 | - [Multiple middleware](https://github.com/understanding-astro/astro-middleware-examples/tree/master/multiple-middleware)
11 | - [Feature flag (PostHog)](https://github.com/understanding-astro/astro-middleware-examples/tree/master/feature-flag-posthog)
12 | - Coming soon ...
13 |
14 | ## 🧞 Commands
15 |
16 | Change directory to the required example and run any of the following commands from a terminal:
17 |
18 | | Command | Action |
19 | | :------------------------ | :----------------------------------------------- |
20 | | `npm install` | Installs dependencies |
21 | | `npm run dev` | Starts local dev server at `localhost:3000` |
22 | | `npm run build` | Build your production site to `./dist/` |
23 | | `npm run preview` | Preview your build locally, before deploying |
24 | | `npm run astro ...` | Run CLI commands like `astro add`, `astro check` |
25 | | `npm run astro -- --help` | Get help using the Astro CLI |
26 |
--------------------------------------------------------------------------------
/feature-flag-posthog/src/middleware.ts:
--------------------------------------------------------------------------------
1 | import { defineMiddleware } from "astro:middleware";
2 |
3 | import { PostHog } from "posthog-node";
4 |
5 | const HOME_PAGE_PATH = "/";
6 |
7 | /**
8 | * Create the Post hog client and pass your project API key
9 | * Add POSTHOG_CLIENT to "src/.env"
10 | */
11 | const client = new PostHog(import.meta.env.POSTHOG_CLIENT);
12 |
13 | export const onRequest = defineMiddleware(async (context, next) => {
14 | /**
15 | * Early return. We will only check the feature flag with requests
16 | * to the homepage
17 | */
18 | if (context.url.pathname !== HOME_PAGE_PATH) {
19 | return next();
20 | }
21 |
22 | try {
23 | /**
24 | * Retrieve the feature toggle for your feature flag
25 | * In this case, "astro-middleware-demo"
26 | */
27 | const isEnabled = await client.isFeatureEnabled(
28 | "astro-middleware-demo",
29 | "" // Pass a static-user-id
30 | );
31 |
32 | console.log({ isEnabled });
33 |
34 | if (isEnabled) {
35 | console.log("Feature is ENABLED!");
36 |
37 | /**
38 | * When the feature flag is toggled on, redirect users who access the homepage,
39 | * to the "/post-hog" page
40 | */
41 | return Response.redirect(new URL("/post-hog", context.url), 302);
42 |
43 | /**
44 | * Otherwise, handle the request as usual
45 | */
46 | return next();
47 | }
48 |
49 | /**
50 | * Feature flag NOT enabled? Handle the request as usual
51 | */
52 |
53 | console.log("Feature is DISABLED!");
54 | return next();
55 | } catch (error) {
56 | console.error("Failed to load feature flag from PostHog");
57 |
58 | /**
59 | * Handle the request as usual
60 | */
61 | return next();
62 | }
63 | });
64 |
--------------------------------------------------------------------------------
/jwt-auth/src/middleware.ts:
--------------------------------------------------------------------------------
1 | import { errors, jwtVerify } from "jose";
2 | import { defineMiddleware } from "astro/middleware";
3 | import { TOKEN, PUBLIC_ROUTES } from "./constant";
4 |
5 | const secret = new TextEncoder().encode(import.meta.env.JWT_SECRET_KEY);
6 |
7 | const verifyAuth = async (token?: string) => {
8 | if (!token) {
9 | return {
10 | status: "unauthorized",
11 | msg: "please pass a request token",
12 | } as const;
13 | }
14 |
15 | try {
16 | const jwtVerifyResult = await jwtVerify(token, secret);
17 |
18 | return {
19 | status: "authorized",
20 | payload: jwtVerifyResult.payload,
21 | msg: "successfully verified auth token",
22 | } as const;
23 | } catch (err) {
24 | if (err instanceof errors.JOSEError) {
25 | return { status: "error", msg: err.message } as const;
26 | }
27 |
28 | console.debug(err);
29 | return { status: "error", msg: "could not validate auth token" } as const;
30 | }
31 | };
32 |
33 | export const onRequest = defineMiddleware(async (context, next) => {
34 | // Ignore auth validation for public routes
35 | if (PUBLIC_ROUTES.includes(context.url.pathname)) {
36 | return next();
37 | }
38 |
39 | const token = context.cookies.get(TOKEN).value;
40 | const validationResult = await verifyAuth(token);
41 |
42 | console.log(validationResult);
43 |
44 | switch (validationResult.status) {
45 | case "authorized":
46 | return next();
47 |
48 | case "error":
49 | case "unauthorized":
50 | if (context.url.pathname.startsWith("/api/")) {
51 | return new Response(JSON.stringify({ message: validationResult.msg }), {
52 | status: 401,
53 | });
54 | }
55 | // otherwise, redirect to the root page for the user to login
56 | else {
57 | return Response.redirect(new URL("/", context.url));
58 | }
59 |
60 | default:
61 | return Response.redirect(new URL("/", context.url));
62 | }
63 | });
64 |
--------------------------------------------------------------------------------
/feature-flag-posthog/README.md:
--------------------------------------------------------------------------------
1 | # Astro Starter Kit: Basics
2 |
3 | ```
4 | npm create astro@latest -- --template basics
5 | ```
6 |
7 | [](https://stackblitz.com/github/withastro/astro/tree/latest/examples/basics)
8 | [](https://codesandbox.io/p/sandbox/github/withastro/astro/tree/latest/examples/basics)
9 | [](https://codespaces.new/withastro/astro?devcontainer_path=.devcontainer/basics/devcontainer.json)
10 |
11 | > 🧑🚀 **Seasoned astronaut?** Delete this file. Have fun!
12 |
13 | 
14 |
15 | ## 🚀 Project Structure
16 |
17 | Inside of your Astro project, you'll see the following folders and files:
18 |
19 | ```
20 | /
21 | ├── public/
22 | │ └── favicon.svg
23 | ├── src/
24 | │ ├── components/
25 | │ │ └── Card.astro
26 | │ ├── layouts/
27 | │ │ └── Layout.astro
28 | │ └── pages/
29 | │ └── index.astro
30 | └── package.json
31 | ```
32 |
33 | Astro looks for `.astro` or `.md` files in the `src/pages/` directory. Each page is exposed as a route based on its file name.
34 |
35 | There's nothing special about `src/components/`, but that's where we like to put any Astro/React/Vue/Svelte/Preact components.
36 |
37 | Any static assets, like images, can be placed in the `public/` directory.
38 |
39 | ## 🧞 Commands
40 |
41 | All commands are run from the root of the project, from a terminal:
42 |
43 | | Command | Action |
44 | | :------------------------ | :----------------------------------------------- |
45 | | `npm install` | Installs dependencies |
46 | | `npm run dev` | Starts local dev server at `localhost:4321` |
47 | | `npm run build` | Build your production site to `./dist/` |
48 | | `npm run preview` | Preview your build locally, before deploying |
49 | | `npm run astro ...` | Run CLI commands like `astro add`, `astro check` |
50 | | `npm run astro -- --help` | Get help using the Astro CLI |
51 |
52 | ## 👀 Want to learn more?
53 |
54 | Feel free to check [our documentation](https://docs.astro.build) or jump into our [Discord server](https://astro.build/chat).
55 |
--------------------------------------------------------------------------------
/feature-flag-posthog/src/pages/post-hog.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import Layout from "../layouts/Layout.astro";
3 | import Card from "../components/Card.astro";
4 | ---
5 |
6 |
7 |
8 | Welcome to the PostHog AB test
9 |
10 | If you're seeing this page, it means the feature flag is enabled and
11 | you've been automatically redirected!
12 |
13 |
14 | Code Challenge: Tweak the feature flag implementation
15 | in src/middleware.ts
16 |
17 |
18 |
30 |
31 |
32 |
33 |
94 |
--------------------------------------------------------------------------------
/redirect/src/pages/redirected.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import Layout from "../layouts/Layout.astro";
3 | ---
4 |
5 |
6 |
7 |
16 |
21 |
22 |
30 |
31 |
32 |
33 |
34 |
35 | You've been Redirected
36 |
37 | The redirect is handled by the middleware in src/middleware.ts
39 |
40 | Code Challenge: Tweak the redirect URL to www.google.com
43 |
44 |
45 |
46 |
47 |
102 |
--------------------------------------------------------------------------------
/multiple-middleware/src/pages/index.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import Layout from "../layouts/Layout.astro";
3 | ---
4 |
5 |
6 |
7 |
16 |
21 |
22 |
30 |
31 |
32 |
33 |
34 |
35 |
36 | Welcome to Astro multiple middleware example
37 |
38 |
39 | Check the server logs and you should see logs from multiple middleware
41 | Code Challenge: Tweak the server "log" messages.
42 |
43 |
44 |
45 |
46 |
107 |
--------------------------------------------------------------------------------
/redirect/src/pages/index.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import Layout from "../layouts/Layout.astro";
3 | ---
4 |
5 |
6 |
7 |
16 |
21 |
22 |
30 |
31 |
32 |
33 |
34 |
35 | Welcome to Astro
36 |
37 | To get started, open the directory src/pages in your project.
39 | Code Challenge: Tweak the "Welcome to Astro" message above.
40 |
41 |
42 |
43 |
44 |
45 |
106 |
--------------------------------------------------------------------------------
/locals-object/src/pages/index.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import Layout from "../layouts/Layout.astro";
3 |
4 | const data = Astro.locals;
5 |
6 | console.log({ res: data.functionValue() });
7 | ---
8 |
9 |
10 |
11 |
20 |
25 |
26 |
34 |
35 |
36 |
37 |
38 |
39 |
40 | Welcome to Astro locals middleware example
41 |
42 |
43 | The data below came from a middleware:
44 |
45 | {JSON.stringify(data, null, 2)}
46 |
47 |
48 | Code Challenge: Tweak the locals object in src/middleware.ts
51 |
52 |
53 |
54 |
55 |
116 |
--------------------------------------------------------------------------------
/feature-flag-posthog/src/pages/index.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import Layout from "../layouts/Layout.astro";
3 | import Card from "../components/Card.astro";
4 | ---
5 |
6 |
7 |
8 |
17 |
22 |
23 |
31 |
32 |
33 |
34 |
35 |
36 | Welcome to Astro
37 |
38 | To get started, open the directory src/pages in your project.
40 | Code Challenge: Tweak the "Welcome to Astro" message
41 | above.
42 |
43 |
65 |
66 |
67 |
68 |
129 |
--------------------------------------------------------------------------------
/jwt-auth/src/pages/protected.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import Layout from "../layouts/Layout.astro";
3 | ---
4 |
5 |
6 |
7 |
16 |
21 |
22 |
30 |
31 |
32 |
33 |
34 |
35 |
36 | This page is protected
37 |
38 |
39 |
You're logged in!
40 |
41 | This page cannot reach it unless you have the{" "}
42 | user token JWT Cookie. Don't have the cookie? You will be redirected
43 | to the{" "}
44 | index page .
45 |
46 |
47 |
48 |
49 | Click the logout button to unset the JWT cookie
50 |
51 | Logout
52 |
53 |
54 |
55 |
56 |
57 |
124 |
125 |
144 |
--------------------------------------------------------------------------------
/jwt-auth/src/pages/index.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import Layout from "../layouts/Layout.astro";
3 | ---
4 |
5 |
6 |
7 |
16 |
21 |
22 |
30 |
31 |
32 |
33 |
34 |
35 |
36 | Welcome to the Astro JWT Middleware example
37 |
38 |
39 |
40 |
41 | Authentication is done via a JWT in your project.
46 |
47 |
48 |
49 | Login
50 |
51 |
52 |
53 | If you're not logged in i.e., without a valid token set, you wont be
54 | able to vist the protected resources below:
55 |
56 |
57 |
65 |
66 |
67 |
68 |
69 |
136 |
137 |
156 |
--------------------------------------------------------------------------------