-
Notifications
You must be signed in to change notification settings - Fork 0
Security
- Never hardcode API keys, passwords, or tokens in code.
- Store secrets in environment variables.
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.
- Restrict which domains can make requests to the API.
- Specify allowed methods and headers.
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"],
}),
);- Implement 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.
From the feature/backend-user-authentication branch, the auth-middleware functions store 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();
};
// 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();
};You must be an authenticated and authorized user to access certain pages.
- Set cookies with
Secureflag, 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.
From the feature/backend-user-authentication branch, 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,
}),
],
});- Never store passwords in plain text.
- Use a strong hashing algorithm.
The Better-Auth library handles this internally using the scrypt algorithm.
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.
As the project develops, we will include:
- Input sanitation and validation
- Rate-limiting
- Email verification
And we may explore:
- Multi-factor authentication (MFA) for user accounts