Skip to content
This repository was archived by the owner on May 9, 2026. It is now read-only.

Security

Sloan edited this page Dec 23, 2025 · 6 revisions

Overview

This project integrates the Better-Auth library for TypeScript, which provides a secure authentication system with session management, cookie-based auth, password hashing, email verification, account linking, and more.

Our integration consists of four main parts:

  • The Database Schema (backend/src/db/schema.ts): We use the Drizzle adapter with Better-Auth tables user, session, account, and verification for account and session handling. All primary keys and foreign keys for users are set to Text (UUIDs) to maintain compatibility with Better-Auth's internal logic.
  • The Auth Server (backend/src/lib/auth.ts): This is where the Better-Auth engine is configured, defining how the server handles credentials and session rules.
  • The Auth Client (frontend/lib/auth-client.ts): A specialized API wrapper that allows our Expo app to communicate with the backend auth endpoints using a type-safe SDK (e.g. authClient.signIn.email()).
  • The Auth Middleware (backend/src/middleware/auth-middleware.ts): Custom Hono middleware that extracts Better-Auth's session cookies from incoming requests to identify and authorize users for protected routes.

Login Flow:

  1. Request: The Expo app sends a login request via the Auth Client.
  2. Processing: The Better-Auth handler on the Hono server intercepts the request, validates credentials, and creates a session.
  3. Response: The Better-Auth handler sends back a Set-Cookie header.
  4. Subsequent Calls: For all future API calls, the cookie is automatically attached by the native networking stack. Our Auth Middleware captures the user session on the backend to control access to protected endpoints.

More details, including security concerns and Better-Auth code implementation details are listed below...

1. Secure Storage of Secrets

Steps to Mitigate Concern

  • Never hardcode API keys, passwords, or tokens in code.
  • Store secrets in environment variables.

Code Implementation

The env.example.prod file lists important credentials, for example:

# --- Database (aero_db) ---
POSTGRES_USER=admin
POSTGRES_PASSWORD=CHANGE_ME_PASSWORD
POSTGRES_DB=aero_prod_db
DATABASE_URL=postgresql://admin:CHANGE_ME_PASSWORD@db:5432/aero_prod_db

Publicly, only placeholders are used. Locally, they are replaced with the real values. These credentials and others are never hardcoded or revealed elsewhere.

2. Cross-Origin Resource Sharing (CORS) Configuration

Steps to Mitigate Concern

  • Restrict which domains can make requests to the API.
  • Specify allowed methods and headers.

Code Implementation

CORS is configured in the backend so that only trusted origins can access the API endpoints.

app.use(
  "/api/*", // Only apply CORS to the API routes
  cors({
    origin: [
      "https://aero.com",
      "http://localhost:3000", // For testing the local production build
      "http://localhost:8081", // For the local Expo dev server (npm start)
    ],
    allowMethods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
    allowHeaders: ["Content-Type", "Authorization"],
  }),
);

3. Authentication & Authorization

Steps to Mitigate Concern

  • Integrate Better-Auth, which is a well-trusted and well-tested authentication library.
  • Better-Auth provides a built-in session handler to validate users.
  • Backend custom middleware runs on every API request to store the user and their session.
  • If a particular user is invalid, they are blocked from certain pages.

Code Implementation

In backend/src/middleware/auth-middleware.ts, the following function stores a user and their session, and validates it on every request:

// Authentication: Stores user and session ID in context for later use. Runs on every request
export const authMiddleware = async (c: Context, next: Next) => {
  const session = await auth.api.getSession({ headers: c.req.raw.headers }); // Extract session cookie

  if (!session) {
    // No valid session, user not logged in
    c.set("user", null);
    c.set("session", null);
    await next();
    return;
  }
  // Valid session, store user and session ID to make available in all subsequent routes
  c.set("user", session.user);
  c.set("session", session.session);
  await next();
};

The following function is run by default on every request so that you must be a validated user to access any endpoint:

// Authorization: Require user to be authenticated
export const requireAuth = async (c: Context, next: Next) => {
  const user = c.get("user");

  if (!user) {
    return c.json({ error: "User not logged in" }, 401);
  }
  await next();
};

The following function runs on public endpoints that do not require authentication such as the login page or home page:

// No authentication required for public routes
export const publicNoAuth = async (c: Context, next: Next) => {
  c.set("noAuthRequired", true);
  await next();
};

4. Cookie Security

Steps to Mitigate Concern

  • Set cookies with Secure flag, meaning cookies can only be sent over HTTPS.
  • Expire sessions after logout or after an extended period of time (handled by Better-Auth).
  • Handle cookies securely in frontend using secure storage.

Code Implementation

In frontend/lib/auth-client.ts, the frontend implements the authClient for Expo from the Better-Auth library where cookies are handled and stored using SecureStore.

export const authClient = createAuthClient ({
    baseURL: "https://localhost:3001", // Backend URL
    plugins: [
        expoClient({
            scheme: "frontend",
            storagePrefix: "frontend",
            storage: SecureStore,
        }),
    ],
});

5. Password Storage & Hashing

Steps to Mitigate Concern

  • Never store passwords in plain text.
  • Use a strong hashing algorithm.

Code Implementation

The Better-Auth library handles this internally using the scrypt algorithm.

Note on Better-Auth

Important security features of the Better-Auth library is explained here. Using the Better-Auth library over custom security implementations is safer and more secure because the library is battle-tested and maintained by security experts, reducing the risk of common mistakes like weak hashing, insecure cookie handling, or insecure session handling. It provides a maintained, auditable solution that follows industry best practices.

Future Security Enhancements

As the project develops, we will include:

  • Input sanitation and validation on custom routes (Better-Auth sanitizes and validates internal auth routes only)
  • Rate-limiting (not included in Better-Auth library)
  • Brute Force Protection (not included in Better-Auth library)
  • Email verification

And we may explore:

  • Multi-factor authentication (MFA) for user accounts

Clone this wiki locally