Part 2: Control access
The host from Part 1 accepts requests from anyone. Add a single shared credential so only people who have it can use the host. This part changes access to the existing repositories; it does not recreate them.
Generate the credential
Section titled “Generate the credential”Create src/secret.ts:
import * as Alchemy from "alchemy";import * as Effect from "effect/Effect";
export const GitSecret = Effect.gen(function* () { const Random = yield* Alchemy.Random; return yield* Random("GitSecret");});Alchemy creates this random value on the first deploy and keeps it stable across updates. It is the password Git clients will send.
Check the password on each request
Section titled “Check the password on each request”Create src/middleware.ts:
import { RuntimeContext } from "alchemy";import * as Effect from "effect/Effect";import * as Redacted from "effect/Redacted";import * as HttpRouter from "effect/unstable/http/HttpRouter";import * as HttpServerResponse from "effect/unstable/http/HttpServerResponse";import * as HttpApiBuilder from "effect/unstable/httpapi/HttpApiBuilder";import * as HttpApiSecurity from "effect/unstable/httpapi/HttpApiSecurity";import { GitSecret } from "./secret.ts";
export const Authentication = HttpRouter.middleware( Effect.gen(function* () { const secret = yield* (yield* GitSecret).text; return (httpEffect) => Effect.gen(function* () { const { password } = yield* HttpApiBuilder.securityDecode( HttpApiSecurity.basic, ); if (Redacted.value(password) === Redacted.value(yield* secret)) { return yield* httpEffect; } return HttpServerResponse.empty({ status: 401, headers: { "www-authenticate": 'Basic realm="git"' }, }); }).pipe(Effect.provide(RuntimeContext.phantom)); }),);HTTP Basic has a username and password. This policy ignores the username and
checks the password. A matching credential continues to the Git handler; other
requests receive 401. WWW-Authenticate tells Git to prompt for a credential.
The Worker supplies RuntimeContext per request; the phantom layer accounts for
that service in the middleware’s type.
Apply the check to Git’s routes
Section titled “Apply the check to Git’s routes”import * as Layer from "effect/Layer";import { Authentication } from "./middleware.ts";Replace the start of the route assembly:
export const GitLive = Git.ApiLive.pipe(const PublicRoutes = Git.ApiLive.pipe( Layer.provide(Authentication.layer),);
export const GitLive = PublicRoutes.pipe( Layer.provide(Git.ApiHandlersLive),PublicRoutes means the routes exposed to Git and API clients. They now all pass
through your middleware, including repository management, pushes, and clones.
Output the credential
Section titled “Output the credential”Add these imports to alchemy.run.ts:
import * as Effect from "effect/Effect";import * as Output from "alchemy/Output";import * as Redacted from "effect/Redacted";import { GitSecret } from "./src/secret.ts";Then include the generated value in the stack’s outputs:
const host = yield* GitHost; return { url: host.url.as<string>() }; const secret = yield* GitSecret; return { url: host.url.as<string>(), secret: Output.map(secret.text, Redacted.value), };This exposes the shared credential in the deployment output so you can copy it for the tutorial. Anyone with this credential has full access to the host.
Deploy the access policy
Section titled “Deploy the access policy”bun alchemy deploynpx alchemy deploypnpm alchemy deployyarn alchemy deployCopy the printed credential:
export GIT_SECRET="paste-the-secret-output"Keep $HOST from Part 1. The Worker URL and acme/web repository are unchanged.
Verify that anonymous requests fail
Section titled “Verify that anonymous requests fail”curl -i "$HOST/api/v1/repos"Expect 401 and a WWW-Authenticate: Basic realm="git" header. If you still see
the old 200 response immediately after deploying, repeat this check while the
update propagates; access is protected only once the new policy is serving.
The same request
with the credential succeeds:
curl --fail-with-body -u "x:$GIT_SECRET" "$HOST/api/v1/repos"You should see the repository created in Part 1.
Push with the credential
Section titled “Push with the credential”printf 'Access is now protected.\n' >> work/README.mdgit -C work commit -am "Require a credential"git -c credential.helper= -C work push origin mainWhen prompted, enter x as the username and the value of $GIT_SECRET as the
password. The push should succeed. Clone with the same credentials to verify
that authenticated reads work too:
git -c credential.helper= clone "$HOST/acme/web.git" private-copygit -C private-copy fsck --strictContinue to Part 3: Publish a repository, where reads of public repositories become available without the shared credential.