Skip to content
RELKIT
Esc
↑↓navigate↵open⌘Jpreview
On this page

Test authentication

Verify migrated auth storage, public and protected requests, sign-in failures, and session invalidation without touching development accounts.

Test sign-in and protected requests with an isolated database and the real authentication handler. A mocked session is useful for a business permission test, but it does not prove sign-in, cookies, migrations, or route protection work together.

Test the complete local flow

The executable test migrates a temporary SQLite file before starting the application. It supplies both RELKIT’s parsed environment and Better Auth’s process environment, then restores process values and removes only its temporary directory after closing the application:

Complete auth integration test

Import createTestApplication from @relkit/testing/better-auth for this database-backed auth application. A database-only application uses @relkit/testing/drizzle; the general @relkit/testing harness does not install either SDK. Keep the selected integration and native SDK packages in the application’s dependencies, as shown in Better Auth setup.

Run from the repository’s examples/auth-drizzle directory:

bun test tests/auth.test.ts

The assertions cover:

  • Applying the checked-in migration and safely applying it again.
  • Anonymous access to public /session and rejection at protected /account/profile.
  • Email/password sign-up, the resulting cookie, and authenticated application/native session reads.
  • Sign-out followed by rejection of the old session cookie on a new request.
  • Rejection of a wrong password and successful subsequent sign-in.

The HTTP harness does not store browser cookies automatically; the test forwards the returned cookie explicitly. It does not read the developer’s cookie jar or mutate ./auth.sqlite.

Keep test state isolated

Create the environment before loading the auth service: its baseURL option is evaluated when the module loads, while the omitted secret uses Better Auth’s process-environment lookup at activation. Passing only createTestApplication(..., { env: ... }) does not update that native process environment.

The selected test harness acquires isolated database and auth owners for each application and closes them independently. It leaves the lazy descriptor’s shared handler target untouched. Explicit activateBetterAuthService calls outside this harness share the first activation by default; use its isolated option when independently owning a borrowed database. Do not run process-environment mutations concurrently within the same process.

The harness clock is not a promise that native Better Auth time or browser expiry is simulated. For expiry/refresh policy tests, use a controlled configuration and time strategy appropriate to the native library, then check the resulting HTTP behavior.

Test business permissions separately

For a domain function, use function testing with an explicit context.auth.getSession result. Test at least an anonymous caller, the resource owner, and another authenticated caller. Assert that denied requests do not read or mutate protected data.

Do not let a fake “authenticated” result bypass ownership or membership checks. If the operation is reachable through jobs, tools, or direct invocation, test that transport’s identity contract as well; HTTP route protection is not the only entry point.

Verify browser and deployment behavior

The native library relaxes origin checks in its test environment, and this harness is not a browser. A passing Bun test does not prove production origin validation, HTTPS cookies, CORS, or OAuth redirects. Run the application and exercise sign-up, sign-in, sign-out, and protected access in a real browser.

For your deployment, add checks for hostile origins, expired/revoked sessions, stable secrets across replicas, password-reset and verification links, rate limits, and any enabled providers/plugins. Run migration tests against the production dialect and an isolated database. Never point these tests at live customer accounts.

Diagnose common failures

Symptom Check first
Compiler rejects auth registration One Drizzle service, one auth service, and one recognized ALL catch-all mount
Auth tables are missing Same database path/schema for app and migrations; migration ran before startup
Service handler returns 503 Use runtime activation through the app, not the descriptor as a standalone server
Sign-in succeeds but profile returns 401 Cookie sent on the next request, consistent hostname, correct public URL and cookie policy
Auth callback/origin is rejected Actual baseURL, mounted path, exact trusted origins, and provider callback registration
/session reports signed out This is a public optional-session function; inspect whether the request carries a valid cookie
Session type is missing Run bun run check, inspect the generated registry, then typecheck
A signed-in user sees another user’s data Add/test business authorization; route protection only checks authentication

Use status codes and redacted diagnostics during investigation. Do not print passwords, auth tokens, or entire request headers to troubleshoot a cookie problem.

Reference and source