Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 19 additions & 3 deletions apps/auth/app.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
// Auth service using Express
import { config } from 'dotenv';
const dotenvResult = config();

Check warning on line 3 in apps/auth/app.ts

View workflow job for this annotation

GitHub Actions / lint-and-typecheck

'dotenvResult' is assigned a value but never used

import { auth } from '@wxyc/authentication';
import { toNodeHandler } from 'better-auth/node';
import cors from 'cors';
import express from 'express';
import rateLimit from 'express-rate-limit';

const port = process.env.AUTH_PORT || '8080';

Expand Down Expand Up @@ -51,7 +52,7 @@
}

const userId = userResult[0].id;
const tokenPrefix = `${type}:`;

Check warning on line 55 in apps/auth/app.ts

View workflow job for this annotation

GitHub Actions / lint-and-typecheck

Invalid type "string | ParsedQs | (string | ParsedQs)[]" of template literal expression

Check warning on line 55 in apps/auth/app.ts

View workflow job for this annotation

GitHub Actions / lint-and-typecheck

'type' may use Object's default stringification format ('[object Object]') when stringified
const result = await db
.select()
.from(verification)
Expand All @@ -60,7 +61,7 @@
.limit(1);

if (result.length === 0) {
return res.status(404).json({ error: `No ${type} token found for this user` });

Check warning on line 64 in apps/auth/app.ts

View workflow job for this annotation

GitHub Actions / lint-and-typecheck

Invalid type "string | ParsedQs | (string | ParsedQs)[]" of template literal expression

Check warning on line 64 in apps/auth/app.ts

View workflow job for this annotation

GitHub Actions / lint-and-typecheck

'type' may use Object's default stringification format ('[object Object]') when stringified
}

// Extract the actual token from the identifier (e.g., "reset-password:abc123" -> "abc123")
Expand All @@ -81,7 +82,7 @@
// Expire a user's session for testing session timeout
app.post('/auth/test/expire-session', async (req, res) => {
try {
const { userId } = req.body;

Check warning on line 85 in apps/auth/app.ts

View workflow job for this annotation

GitHub Actions / lint-and-typecheck

Unsafe assignment of an `any` value
if (!userId || typeof userId !== 'string') {
return res.status(400).json({ error: 'userId is required in request body' });
}
Expand All @@ -107,9 +108,24 @@
);
}

// Mount the Better Auth handler for all auth routes
// app.use() will handle all methods and paths under /auth
app.use('/auth', toNodeHandler(auth));
// Disable rate limiting in test environments to avoid flaky integration tests.
// This matches the pattern used by the backend's rateLimiting middleware.
const isTestEnv =
process.env.NODE_ENV === 'test' || process.env.USE_MOCK_SERVICES === 'true' || process.env.AUTH_BYPASS === 'true';

if (isTestEnv) {
app.use('/auth', toNodeHandler(auth));
} else {
const authRateLimit = rateLimit({
windowMs: 15 * 60 * 1000,
limit: 10,
standardHeaders: 'draft-7',
legacyHeaders: false,
message: { error: 'Too many requests, please try again later.' },
});

app.use('/auth', authRateLimit, toNodeHandler(auth));
}

//endpoint for healthchecks
app.get('/healthcheck', async (req, res) => {
Expand All @@ -119,7 +135,7 @@
const response = await fetch(`${authServiceUrl}/auth/ok`);

// Forward the status and body from the /auth/ok response
const data = await response.json(); // Assuming /auth/ok returns JSON

Check warning on line 138 in apps/auth/app.ts

View workflow job for this annotation

GitHub Actions / lint-and-typecheck

Unsafe assignment of an `any` value
res.status(response.status).json(data);
} catch (error) {
console.error('Error proxying /healthcheck to /auth/ok:', error);
Expand Down Expand Up @@ -201,7 +217,7 @@
},
});

organizationId = newOrganization.id;

Check warning on line 220 in apps/auth/app.ts

View workflow job for this annotation

GitHub Actions / lint-and-typecheck

Unsafe assignment of an `any` value
}

if (!organizationId) {
Expand All @@ -212,7 +228,7 @@
model: 'member',
where: [
{ field: 'userId', value: newUser.id },
{ field: 'organizationId', value: organizationId },

Check warning on line 231 in apps/auth/app.ts

View workflow job for this annotation

GitHub Actions / lint-and-typecheck

Unsafe assignment of an `any` value
],
});

Expand All @@ -224,7 +240,7 @@
model: 'member',
data: {
userId: newUser.id,
organizationId: organizationId,

Check warning on line 243 in apps/auth/app.ts

View workflow job for this annotation

GitHub Actions / lint-and-typecheck

Unsafe assignment of an `any` value
role: 'stationManager',
createdAt: new Date(),
},
Expand Down
5 changes: 3 additions & 2 deletions apps/auth/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,13 @@
"author": "Jackson Meade",
"license": "MIT",
"dependencies": {
"@wxyc/database": "^1.0.0",
"@wxyc/authentication": "^1.0.0",
"@wxyc/database": "^1.0.0",
"better-auth": "^1.3.23",
"cors": "^2.8.5",
"dotenv": "^17.2.1",
"express": "^5.1.0"
"express": "^5.1.0",
"express-rate-limit": "^8.2.1"
},
"peerDependencies": {
"drizzle-orm": "^0.41.0"
Expand Down
3 changes: 0 additions & 3 deletions apps/auth/tsup.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,5 @@ export default defineConfig((options) => ({
clean: true,
sourcemap: true,
external: ['@wxyc/database', 'better-auth', 'drizzle-orm', 'express', 'cors', 'postgres'],
env: {
NODE_ENV: process.env.NODE_ENV || 'development',
},
onSuccess: options.watch ? 'node ./dist/app.js' : undefined,
}));
1 change: 1 addition & 0 deletions dev_env/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ services:
dockerfile: Dockerfile.auth
profiles: [ci]
environment:
- NODE_ENV=test
- DB_HOST=ci-db
- DB_PORT=5432
- DB_USERNAME=${DB_USERNAME}
Expand Down
3 changes: 2 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 25 additions & 0 deletions tests/unit/auth/rate-limiting.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { readFileSync } from 'fs';
import { resolve } from 'path';

describe('Auth service rate limiting', () => {
const authAppSource = readFileSync(resolve(__dirname, '../../../apps/auth/app.ts'), 'utf-8');

it('imports express-rate-limit', () => {
expect(authAppSource).toMatch(/express-rate-limit/);
});

it('configures a rate limiter with rateLimit()', () => {
expect(authAppSource).toMatch(/rateLimit\s*\(/);
});

it('applies rate limiting to the auth handler in production', () => {
// The rate limiter is applied conditionally: skipped in test env, active otherwise.
// Verify the production branch wires authRateLimit before toNodeHandler(auth).
expect(authAppSource).toMatch(/authRateLimit,\s*toNodeHandler\s*\(\s*auth\s*\)/);
});

it('disables rate limiting in test environments', () => {
expect(authAppSource).toMatch(/isTestEnv/);
expect(authAppSource).toMatch(/NODE_ENV.*test|USE_MOCK_SERVICES/);
});
});
Loading