Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
- id: proxy-wasm-sdk-as
ref: master
commit: 8e3bb621bc013a0aed7e52122066b417ad62a207
updated: 2026-08-17
updated: 2026-08-20
-->

# A/B Testing — AssemblyScript (CDN)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
- id: proxy-wasm-sdk-as
ref: master
commit: 8e3bb621bc013a0aed7e52122066b417ad62a207
updated: 2026-08-17
updated: 2026-08-20
-->

---
Expand Down Expand Up @@ -199,168 +199,3 @@ Upload `build/apiKey.wasm` to the FastEdge portal and attach it to a CDN applica
- proxy-wasm-sdk-as reference (full `Context`, `RootContext`, `FilterHeadersStatusValues` API)
- FastEdge secrets management (how to set and rotate application secrets)
- CDN app deployment guide

## Source Material

### FILE: examples/apiKey/assembly/index.ts

```ts
export * from "@gcoredev/proxy-wasm-sdk-as/assembly/proxy";
import {
Context,
FilterHeadersStatusValues,
HeaderPair,
log,
LogLevelValues,
makeHeaderPair,
registerRootContext,
RootContext,
send_http_response,
stream_context,
} from "@gcoredev/proxy-wasm-sdk-as/assembly";
import {
getSecret,
setLogLevel,
} from "@gcoredev/proxy-wasm-sdk-as/assembly/fastedge";

const UNAUTHORIZED: u32 = 401;
const FORBIDDEN: u32 = 403;
const INTERNAL_SERVER_ERROR: u32 = 500;

class ApiKeyRoot extends RootContext {
createContext(context_id: u32): Context {
setLogLevel(LogLevelValues.info);
return new ApiKeyContext(context_id, this);
}
}

class ApiKeyContext extends Context {
constructor(context_id: u32, root_context: ApiKeyRoot) {
super(context_id, root_context);
}

onRequestHeaders(a: u32, end_of_stream: bool): FilterHeadersStatusValues {
const expectedKey = getSecret("API_KEY");
if (expectedKey === "") {
log(LogLevelValues.error, "API_KEY secret not configured");
send_http_response(
INTERNAL_SERVER_ERROR,
"internal server error",
String.UTF8.encode("App misconfigured"),
[],
);
return FilterHeadersStatusValues.StopIteration;
}

const providedKey = stream_context.headers.request.get("X-API-Key");

if (providedKey === "") {
const authHeaders = new Array<HeaderPair>();
authHeaders.push(makeHeaderPair("WWW-Authenticate", "API-Key"));
send_http_response(
UNAUTHORIZED,
"unauthorized",
String.UTF8.encode("Missing X-API-Key header"),
authHeaders,
);
return FilterHeadersStatusValues.StopIteration;
}

if (providedKey !== expectedKey) {
log(LogLevelValues.info, "API key validation failed");
send_http_response(
FORBIDDEN,
"forbidden",
String.UTF8.encode("Invalid API key"),
[],
);
return FilterHeadersStatusValues.StopIteration;
}

// .remove() sets the header value to "" rather than deleting it entirely —
// the upstream will see X-API-Key: "" rather than a missing header.
stream_context.headers.request.remove("X-API-Key");

log(LogLevelValues.info, "API key validated successfully");
return FilterHeadersStatusValues.Continue;
}
}

registerRootContext((context_id: u32) => {
return new ApiKeyRoot(context_id);
}, "apiKey");
```


### FILE: examples/apiKey/package.json

```json
{
"name": "fastedge-as-example-api-key",
"version": "1.0.0",
"description": "FastEdge AssemblyScript example: API Key — validate X-API-Key header against a secret",
"scripts": {
"asbuild:debug": "asc assembly/index.ts --target debug",
"asbuild:release": "asc assembly/index.ts --target release",
"asbuild": "npm run asbuild:debug && npm run asbuild:release"
},
"dependencies": {
"@gcoredev/proxy-wasm-sdk-as": "^1.2.3"
},
"devDependencies": {
"@assemblyscript/wasi-shim": "^0.1.0",
"assemblyscript": "^0.28.9"
}
}
```


### FILE: examples/apiKey/README.md

```
[← Back to examples](../README.md)

# API Key

This application validates requests using an `X-API-Key` header checked against a stored secret.

## What it does

In `onRequestHeaders`, the app:

1. Reads the expected API key from the `API_KEY` secret.
2. Checks the `X-API-Key` request header.
3. Returns `401 Unauthorized` if the header is missing.
4. Returns `403 Forbidden` if the key does not match.
5. On success, clears the `X-API-Key` header before forwarding to the upstream origin (proxy-wasm `.remove()` sets the header value to an empty string rather than deleting it).

This is a simpler alternative to JWT validation when you need basic API authentication without token expiry or claims.

> **Production note:** The key comparison (`providedKey !== expectedKey`) is not constant-time, which opens a timing side-channel for a high-volume attacker. For production use, replace the comparison with a constant-time HMAC equality check or use the `jwt` example which includes proper cryptographic validation.

## Configuration

Set the following on your FastEdge application:

| Name | Type | Description |
|------|------|-------------|
| `API_KEY` | Secret | The expected API key value |

## Build

```sh
pnpm install
pnpm run asbuild
```

Build output:

| File | Description |
|------|-------------|
| `build/apiKey.wasm` | Optimised release binary — upload this to FastEdge |
| `build/apiKey-debug.wasm` | Debug binary with source maps |

## Deploy

Upload `build/apiKey.wasm` to the FastEdge portal and attach it to your CDN application. Configure the `API_KEY` secret in the application settings.
```
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
- id: proxy-wasm-sdk-as
ref: master
commit: 8e3bb621bc013a0aed7e52122066b417ad62a207
updated: 2026-08-17
updated: 2026-08-20
-->
---
capabilities:
Expand Down
Loading