Skip to content

Commit 6208b5e

Browse files
committed
feat: update database configuration for Aiven support and enhance GitHub authentication strategy
1 parent 8cec291 commit 6208b5e

File tree

6 files changed

+84
-36
lines changed

6 files changed

+84
-36
lines changed

Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@ help:
88
@echo "make clean - Stop and remove volumes"
99

1010
up:
11-
docker compose up
11+
docker compose up -d
1212

1313
down:
1414
docker compose down
1515

1616
db:
17-
docker compose up postgres
17+
docker compose up -d postgres
1818

1919
logs:
2020
docker compose logs -f

backend/.env.example

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,23 @@
66
# -----------------------------------------------------------------------------
77
# Database Configuration
88
# -----------------------------------------------------------------------------
9-
# For local development (without Docker): localhost
10-
# For Docker Compose: postgres (service name)
11-
# For production (Aiven): Use Aiven connection details
12-
DB_HOST=localhost
13-
DB_PORT=5432
14-
DB_USERNAME=postgres
15-
DB_PASSWORD=postgres
16-
DB_NAME=learnix
9+
# Option 1: Use DATABASE_URL (recommended for production/Aiven)
10+
# Format: postgres://username:password@host:port/database
11+
# DATABASE_URL=postgres://avnadmin:password@host.aivencloud.com:12345/defaultdb
1712

18-
# SSL Configuration (required for Aiven PostgreSQL in production)
19-
# Set to true for production, false for local development
20-
DB_SSL=false
13+
# Aiven CA Certificate (required for production)
14+
# Copy the content of ca.pem from Aiven Console and paste as a single line
15+
# Or set this in Vercel environment variables
16+
# DATABASE_CA_CERT="-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----"
17+
18+
# Option 2: Use individual variables (for local development)
19+
# If DATABASE_URL is set, these are ignored
20+
# DB_HOST=localhost
21+
# DB_PORT=5432
22+
# DB_USERNAME=postgres
23+
# DB_PASSWORD=postgres
24+
# DB_NAME=learnix
25+
# DB_SSL=false
2126

2227
# -----------------------------------------------------------------------------
2328
# JWT Configuration
@@ -34,11 +39,15 @@ GOOGLE_CLIENT_SECRET=your-google-client-secret
3439
GOOGLE_CALLBACK_URL=http://localhost:3000/auth/google/callback
3540

3641
# -----------------------------------------------------------------------------
37-
# OAuth Configuration - GitHub
38-
# Get these from: https://github.com/settings/developers
42+
# OAuth Configuration - GitHub App (Modern)
43+
# Create a GitHub App at: https://github.com/settings/apps
44+
# Under "Identifying and authorizing users" section:
45+
# - Enable "Request user authorization (OAuth) during installation"
46+
# - Set Callback URL to your callback endpoint
47+
# Required permissions: Account permissions > Email addresses (Read-only)
3948
# -----------------------------------------------------------------------------
40-
GITHUB_CLIENT_ID=your-github-client-id
41-
GITHUB_CLIENT_SECRET=your-github-client-secret
49+
GITHUB_APP_CLIENT_ID=your-github-app-client-id
50+
GITHUB_APP_CLIENT_SECRET=your-github-app-client-secret
4251
GITHUB_CALLBACK_URL=http://localhost:3000/auth/github/callback
4352

4453
# -----------------------------------------------------------------------------

backend/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,6 @@ pids
5454

5555
# Diagnostic reports (https://nodejs.org/api/report.html)
5656
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
57+
58+
# aiven
59+
ca.pem

backend/src/app.module.ts

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,20 +20,42 @@ import { DashboardModule } from './dashboard/dashboard.module';
2020
}),
2121
TypeOrmModule.forRootAsync({
2222
imports: [ConfigModule],
23-
useFactory: (configService: ConfigService) => ({
24-
type: 'postgres',
25-
host: configService.get<string>('DB_HOST'),
26-
port: configService.get<number>('DB_PORT'),
27-
username: configService.get<string>('DB_USERNAME'),
28-
password: configService.get<string>('DB_PASSWORD'),
29-
database: configService.get<string>('DB_NAME'),
30-
entities: [User, ExternalAuth, Quiz, Question],
31-
synchronize: configService.get<string>('NODE_ENV') !== 'production', // Auto-create tables in dev
32-
ssl:
33-
configService.get<string>('DB_SSL') === 'true'
34-
? { rejectUnauthorized: false }
35-
: false,
36-
}),
23+
useFactory: (configService: ConfigService) => {
24+
const databaseUrl = configService.get<string>('DATABASE_URL');
25+
26+
// Use DATABASE_URL if provided (production/Aiven), otherwise use individual vars (local dev)
27+
if (databaseUrl) {
28+
// Aiven SSL configuration with CA certificate
29+
// Replace literal \n with actual newlines (env files store as escaped string)
30+
const caCert = configService.get<string>('DATABASE_CA_CERT');
31+
32+
return {
33+
type: 'postgres',
34+
url: databaseUrl,
35+
entities: [User, ExternalAuth, Quiz, Question],
36+
synchronize: configService.get<string>('NODE_ENV') !== 'production',
37+
ssl: caCert
38+
? { rejectUnauthorized: true, ca: caCert }
39+
: { rejectUnauthorized: false },
40+
};
41+
}
42+
43+
// Fallback to individual environment variables (local development)
44+
return {
45+
type: 'postgres',
46+
host: configService.get<string>('DB_HOST'),
47+
port: configService.get<number>('DB_PORT'),
48+
username: configService.get<string>('DB_USERNAME'),
49+
password: configService.get<string>('DB_PASSWORD'),
50+
database: configService.get<string>('DB_NAME'),
51+
entities: [User, ExternalAuth, Quiz, Question],
52+
synchronize: configService.get<string>('NODE_ENV') !== 'production',
53+
ssl:
54+
configService.get<string>('DB_SSL') === 'true'
55+
? { rejectUnauthorized: false }
56+
: false,
57+
};
58+
},
3759
inject: [ConfigService],
3860
}),
3961
UsersModule,

backend/src/auth/strategies/github.strategy.ts

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,33 @@ import { Strategy, Profile } from 'passport-github2';
33
import { Injectable } from '@nestjs/common';
44
import { ConfigService } from '@nestjs/config';
55

6+
/**
7+
* GitHub App Authentication Strategy
8+
*
9+
* Uses GitHub App OAuth flow (not legacy OAuth App).
10+
* GitHub Apps provide:
11+
* - Granular permissions
12+
* - Higher rate limits
13+
* - Better security with short-lived tokens
14+
*
15+
* Setup: Create a GitHub App at https://github.com/settings/apps
16+
* Required permissions: read:user, user:email
17+
*/
618
@Injectable()
719
export class GithubStrategy extends PassportStrategy(Strategy, 'github') {
820
constructor(private configService: ConfigService) {
921
super({
10-
clientID: configService.get<string>('GITHUB_CLIENT_ID') || 'placeholder',
22+
// GitHub App Client ID (not OAuth App)
23+
clientID:
24+
configService.get<string>('GITHUB_APP_CLIENT_ID') || 'placeholder',
25+
// GitHub App Client Secret
1126
clientSecret:
12-
configService.get<string>('GITHUB_CLIENT_SECRET') || 'placeholder',
27+
configService.get<string>('GITHUB_APP_CLIENT_SECRET') || 'placeholder',
1328
callbackURL:
1429
configService.get<string>('GITHUB_CALLBACK_URL') ||
1530
'http://localhost:3000/auth/github/callback',
16-
scope: ['user:email'],
31+
// Scopes for GitHub App OAuth
32+
scope: ['read:user', 'user:email'],
1733
});
1834
}
1935

docker-compose.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,6 @@ services:
3131
condition: service_healthy
3232
env_file:
3333
- ./backend/.env
34-
environment:
35-
DB_HOST: postgres
3634
volumes:
3735
- ./backend:/app
3836
- backend_node_modules:/app/node_modules

0 commit comments

Comments
 (0)