import assert from "node:assert/strict";
import { mkdtempSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { createServer as createApiServer } from "../apps/api/dist/server.js";
import { createMetadataStore } from "../packages/metadata/dist/index.js";
import { createAuthenticatedTestClient } from "./lib/authenticated-test-client.mjs";
const root = mkdtempSync(join(tmpdir(), "datafoundry-auth-smoke-"));
process.env.AUTH_SESSION_SECRET = "smoke-session-secret-with-at-least-32-bytes";
process.env.AUTH_PUBLIC_BASE_URL = "http://127.0.0.1";
process.env.AUTH_EMAIL_DELIVERY = "test";
process.env.AUTH_REGISTRATION_MODE = "open";
process.env.EMBEDDING_API_KEY = "";
process.env.MASTRA_STORAGE_PATH = join(root, "mastra.sqlite");
process.env.STORAGE_ROOT_DIR = root;
const metadataStore = createMetadataStore({
database_path: join(root, "metadata.sqlite"),
secret_master_key: "auth-smoke-secret-master-key"
});
const server = await createApiServer({ metadataStore });
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
const address = server.address();
assert(address && typeof address === "object");
const baseUrl = `http://127.0.0.1:${address.port}`;
const closeServer = async () => {
await new Promise((resolve, reject) => {
server.close((error) => error ? reject(error) : resolve());
setImmediate(() => server.closeAllConnections?.());
});
};
const client = createAuthenticatedTestClient({ baseUrl });
const requestJson = async (path, init = {}) => {
const response = await client.fetch(path, init);
const body = await response.json();
return { body, response };
};
try {
const anonymousMe = await requestJson("/api/v1/me");
assert.equal(anonymousMe.response.status, 401);
assert.equal(anonymousMe.body.error.code, "UNAUTHORIZED");
const tooShort = await requestJson("/api/v1/auth/register", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
email: "short@example.com",
password: "12345",
displayName: "Too Short"
})
});
assert.equal(tooShort.response.status, 400, JSON.stringify(tooShort.body));
assert.equal(tooShort.body.error.code, "BAD_REQUEST");
assert.match(tooShort.body.error.message, /at least 6 characters/i);
const minLengthOk = await requestJson("/api/v1/auth/register", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
email: "minlen@example.com",
password: "123456",
displayName: "Min Length"
})
});
assert.equal(minLengthOk.response.status, 201, JSON.stringify(minLengthOk.body));
const registered = await requestJson("/api/v1/auth/register", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
email: "alice@example.com",
password: "correct horse battery staple",
displayName: "Alice Analyst"
})
});
assert.equal(registered.response.status, 201, JSON.stringify(registered.body));
assert.equal(typeof registered.body.data.verificationToken, "string");
assert.equal(registered.body.data.user.email, "alice@example.com");
assert.equal("devToken" in registered.body.data.user, false);
const unverifiedLogin = await requestJson("/api/v1/auth/login", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email: "alice@example.com", password: "correct horse battery staple" })
});
assert.equal(unverifiedLogin.response.status, 403);
assert.equal(unverifiedLogin.body.error.code, "EMAIL_NOT_VERIFIED");
const verified = await requestJson("/api/v1/auth/verify-email", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ token: registered.body.data.verificationToken })
});
assert.equal(verified.response.status, 200, JSON.stringify(verified.body));
const loggedIn = await requestJson("/api/v1/auth/login", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email: "alice@example.com", password: "correct horse battery staple" })
});
assert.equal(loggedIn.response.status, 200, JSON.stringify(loggedIn.body));
assert(loggedIn.response.headers.getSetCookie().some((cookie) => /df_session=.*HttpOnly/i.test(cookie)));
assert(loggedIn.response.headers.getSetCookie().some((cookie) => /^df_csrf=/i.test(cookie)));
assert.equal(loggedIn.body.data.user.email, "alice@example.com");
assert.equal("devToken" in loggedIn.body.data.user, false);
assert.match(loggedIn.body.data.workspace.id, /^personal-/);
const me = await requestJson("/api/v1/me");
assert.equal(me.response.status, 200);
assert.equal(me.body.data.user.email, "alice@example.com");
assert.equal(me.body.data.workspace.id, loggedIn.body.data.workspace.id);
const missingCsrf = await requestJson("/api/v1/datasources", {
method: "POST",
headers: { "Content-Type": "application/json", "X-CSRF-Token": "" },
body: JSON.stringify({
id: "alice-sqlite",
name: "Alice SQLite",
type: "sqlite",
settings: { filePath: join(root, "alice.sqlite") }
})
});
assert.equal(missingCsrf.response.status, 403);
assert.equal(missingCsrf.body.error.code, "CSRF_INVALID");
const csrf = client.cookies.csrfToken();
assert(csrf, "Expected login to set a readable CSRF cookie");
const aliceDatasource = await requestJson("/api/v1/datasources", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
id: "alice-sqlite",
name: "Alice SQLite",
type: "sqlite",
settings: { filePath: join(root, "alice.sqlite") }
})
});
assert.equal(aliceDatasource.response.status, 201, JSON.stringify(aliceDatasource.body));
const forgot = await requestJson("/api/v1/auth/password/forgot", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email: "alice@example.com" })
});
assert.equal(forgot.response.status, 200);
assert.equal(typeof forgot.body.data.resetToken, "string");
const reset = await requestJson("/api/v1/auth/password/reset", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
token: forgot.body.data.resetToken,
password: "new correct horse battery staple"
})
});
assert.equal(reset.response.status, 200);
const revokedMe = await requestJson("/api/v1/me");
assert.equal(revokedMe.response.status, 401);
client.cookies.clear();
const relogged = await requestJson("/api/v1/auth/login", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email: "alice@example.com", password: "new correct horse battery staple" })
});
assert.equal(relogged.response.status, 200);
const logout = await requestJson("/api/v1/auth/logout", {
method: "POST"
});
assert.equal(logout.response.status, 200);
const afterLogout = await requestJson("/api/v1/me");
assert.equal(afterLogout.response.status, 401);
console.log(`Auth smoke OK: workspace=${loggedIn.body.data.workspace.id}`);
} finally {
await closeServer();
}