diff --git a/packages/opencode/src/server/routes/instance/httpapi/middleware/authorization.ts b/packages/opencode/src/server/routes/instance/httpapi/middleware/authorization.ts index e022a568ac..05b8738971 100644 --- a/packages/opencode/src/server/routes/instance/httpapi/middleware/authorization.ts +++ b/packages/opencode/src/server/routes/instance/httpapi/middleware/authorization.ts @@ -5,6 +5,7 @@ import { HttpApiError, HttpApiMiddleware, HttpApiSecurity } from "effect/unstabl const AUTH_TOKEN_QUERY = "auth_token" const UNAUTHORIZED = 401 +const WWW_AUTHENTICATE = "Basic realm=\"Secure Area\"" export class Authorization extends HttpApiMiddleware.Service()( "@opencode/ExperimentalHttpApiAuthorization", @@ -82,7 +83,12 @@ function validateRawCredential( ) { if (!isAuthRequired(config)) return effect if (!isCredentialAuthorized(credential, config)) - return Effect.succeed(HttpServerResponse.empty({ status: UNAUTHORIZED })) + return Effect.succeed( + HttpServerResponse.empty({ + status: UNAUTHORIZED, + headers: { "www-authenticate": WWW_AUTHENTICATE }, + }), + ) return effect } diff --git a/packages/opencode/test/server/httpapi-ui.test.ts b/packages/opencode/test/server/httpapi-ui.test.ts index 09b234bde9..1de8a489cd 100644 --- a/packages/opencode/test/server/httpapi-ui.test.ts +++ b/packages/opencode/test/server/httpapi-ui.test.ts @@ -201,6 +201,7 @@ describe("HttpApi UI fallback", () => { const response = await uiApp({ password: "secret", username: "opencode" }).request("/") expect(response.status).toBe(401) + expect(response.headers.get("www-authenticate")).toBe('Basic realm="Secure Area"') }) test("accepts auth token for the web UI", async () => {