@ofeklabs/horizon-auth 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,22 @@
1
1
  # @ofeklabs/horizon-auth
2
2
 
3
- Production-ready NestJS authentication module with 2026 security standards. Add enterprise-grade authentication to your application in under 60 seconds.
3
+ Production-ready NestJS authentication module with 2026 security standards. Deploy once, use everywhere.
4
+
5
+ ## Use Cases
6
+
7
+ ### 1. Portfolio SSO (Recommended)
8
+ Deploy one auth service, use it across all your projects. Users sign in once and access everything.
9
+
10
+ ```
11
+ auth.yourdomain.com (Auth Service)
12
+ ↓ Shared Authentication
13
+ ├── project1.yourdomain.com
14
+ ├── project2.yourdomain.com
15
+ └── project3.yourdomain.com
16
+ ```
17
+
18
+ ### 2. Embedded Auth
19
+ Each application has its own isolated authentication.
4
20
 
5
21
  ## Features
6
22
 
@@ -13,7 +29,73 @@ Production-ready NestJS authentication module with 2026 security standards. Add
13
29
  - 🎯 **Type-Safe**: Full TypeScript support
14
30
  - 📦 **Zero Config**: Sensible defaults, fully customizable
15
31
 
16
- ## Quick Start (60 seconds)
32
+ ## Quick Start
33
+
34
+ ### Portfolio SSO Setup (Recommended)
35
+
36
+ Deploy one auth service, use it across all your projects.
37
+
38
+ #### 1. Deploy Auth Service (One Time)
39
+
40
+ ```bash
41
+ # Clone and deploy packages/horizon-auth to auth.yourdomain.com
42
+ npm install
43
+ npm run build
44
+ npm run start:prod
45
+ ```
46
+
47
+ **Environment Variables**:
48
+ ```env
49
+ DATABASE_URL=postgresql://...
50
+ REDIS_HOST=your-redis-host
51
+ JWT_PRIVATE_KEY=<your-private-key>
52
+ JWT_PUBLIC_KEY=<your-public-key>
53
+ COOKIE_DOMAIN=.yourdomain.com
54
+ NODE_ENV=production
55
+ ```
56
+
57
+ #### 2. Use in Your Projects
58
+
59
+ For each project:
60
+
61
+ ```bash
62
+ npm install @ofeklabs/horizon-auth
63
+ ```
64
+
65
+ ```typescript
66
+ // app.module.ts
67
+ HorizonAuthModule.forRoot({
68
+ ssoMode: true,
69
+ authServiceUrl: process.env.AUTH_SERVICE_URL,
70
+ jwt: {
71
+ publicKey: process.env.JWT_PUBLIC_KEY,
72
+ },
73
+ cookie: {
74
+ domain: process.env.COOKIE_DOMAIN,
75
+ secure: process.env.NODE_ENV === 'production',
76
+ },
77
+ })
78
+ ```
79
+
80
+ ```env
81
+ # .env
82
+ AUTH_SERVICE_URL=https://auth.yourdomain.com
83
+ JWT_PUBLIC_KEY=<paste-public-key>
84
+ COOKIE_DOMAIN=.yourdomain.com
85
+ ```
86
+
87
+ Deploy to:
88
+ - project1.yourdomain.com
89
+ - project2.yourdomain.com
90
+ - project3.yourdomain.com
91
+
92
+ Users sign in once, access all projects.
93
+
94
+ ---
95
+
96
+ ### Embedded Auth Setup (Alternative)
97
+
98
+ Each application has its own authentication.
17
99
 
18
100
  ### 1. Install
19
101
 
@@ -50,10 +132,12 @@ import { join } from 'path';
50
132
  redis: {
51
133
  host: process.env.REDIS_HOST || 'localhost',
52
134
  port: parseInt(process.env.REDIS_PORT) || 6379,
135
+ password: process.env.REDIS_PASSWORD,
53
136
  },
54
137
  jwt: {
55
- privateKey: readFileSync(join(__dirname, '../certs/private.pem'), 'utf8'),
56
- publicKey: readFileSync(join(__dirname, '../certs/public.pem'), 'utf8'),
138
+ // For production: use environment variables
139
+ privateKey: process.env.JWT_PRIVATE_KEY || readFileSync(join(__dirname, '../certs/private.pem'), 'utf8'),
140
+ publicKey: process.env.JWT_PUBLIC_KEY || readFileSync(join(__dirname, '../certs/public.pem'), 'utf8'),
57
141
  },
58
142
  }),
59
143
  ],
@@ -317,10 +401,136 @@ REDIS_HOST=localhost
317
401
  REDIS_PORT=6379
318
402
  REDIS_PASSWORD=your_redis_password
319
403
 
404
+ # JWT Keys (for production - use multiline env vars)
405
+ JWT_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\nMIIE...\n-----END PRIVATE KEY-----"
406
+ JWT_PUBLIC_KEY="-----BEGIN PUBLIC KEY-----\nMIIB...\n-----END PUBLIC KEY-----"
407
+
320
408
  # Application
321
409
  NODE_ENV=production
410
+ PORT=3000
411
+
412
+ # Optional: SSO Mode
413
+ AUTH_SERVICE_URL=https://auth.ofeklabs.dev
414
+ ```
415
+
416
+ ## Production Deployment
417
+
418
+ ### Portfolio SSO Architecture (Recommended)
419
+
420
+ Perfect for portfolios, demo sites, or related projects.
421
+
422
+ **Benefits**:
423
+ - One login for all projects
424
+ - Consistent user experience
425
+ - No duplicate auth code
426
+ - Single point of maintenance
427
+ - Professional appearance
428
+
429
+ **Setup**:
430
+
431
+ 1. Deploy auth service to `auth.yourdomain.com`
432
+ 2. Install package in each project
433
+ 3. Configure SSO mode with `AUTH_SERVICE_URL`
434
+ 4. Deploy projects to subdomains
435
+
436
+ See [PRODUCTION-DEPLOYMENT.md](./PRODUCTION-DEPLOYMENT.md) for complete guide.
437
+
438
+ ### Deploy to Render
439
+
440
+ #### 1. Deploy Auth Service
441
+
442
+ Create a new Web Service on Render:
443
+
444
+ **Environment Variables**:
445
+ ```env
446
+ DATABASE_URL=<your-postgres-url>
447
+ REDIS_HOST=<your-redis-host>
448
+ REDIS_PORT=6379
449
+ REDIS_PASSWORD=<your-redis-password>
450
+ JWT_PRIVATE_KEY=<paste-private-key-with-\n>
451
+ JWT_PUBLIC_KEY=<paste-public-key-with-\n>
452
+ NODE_ENV=production
453
+ COOKIE_DOMAIN=.ofeklabs.dev
454
+ COOKIE_SECURE=true
455
+ ```
456
+
457
+ **Build Command**: `npm install && npm run build`
458
+
459
+ **Start Command**: `npm run start:prod`
460
+
461
+ #### 2. Deploy Your Apps (SSO Mode)
462
+
463
+ For each app (tasks, CRM, analytics):
464
+
465
+ ```typescript
466
+ // app.module.ts
467
+ HorizonAuthModule.forRoot({
468
+ ssoMode: true,
469
+ authServiceUrl: process.env.AUTH_SERVICE_URL || 'https://auth.ofeklabs.dev',
470
+ jwt: {
471
+ publicKey: process.env.JWT_PUBLIC_KEY,
472
+ },
473
+ cookie: {
474
+ domain: process.env.COOKIE_DOMAIN || '.ofeklabs.dev',
475
+ secure: process.env.NODE_ENV === 'production',
476
+ },
477
+ })
478
+ ```
479
+
480
+ **Environment Variables**:
481
+ ```env
482
+ AUTH_SERVICE_URL=https://auth.ofeklabs.dev
483
+ JWT_PUBLIC_KEY=<paste-public-key-with-\n>
484
+ COOKIE_DOMAIN=.ofeklabs.dev
485
+ NODE_ENV=production
486
+ ```
487
+
488
+ #### 3. Configure Custom Domains
489
+
490
+ On Render, add custom domains:
491
+ - Auth service: `auth.ofeklabs.dev`
492
+ - Tasks app: `tasks.ofeklabs.dev`
493
+ - CRM app: `crm.ofeklabs.dev`
494
+
495
+ All apps will share authentication via cookies! 🎉
496
+
497
+ ### Deploy to AWS/Docker
498
+
499
+ ```dockerfile
500
+ FROM node:18-alpine
501
+
502
+ WORKDIR /app
503
+
504
+ COPY package*.json ./
505
+ RUN npm ci --only=production
506
+
507
+ COPY . .
508
+ RUN npm run build
509
+
510
+ EXPOSE 3000
511
+
512
+ CMD ["node", "dist/main"]
322
513
  ```
323
514
 
515
+ ```bash
516
+ # Build and run
517
+ docker build -t horizon-auth .
518
+ docker run -p 3000:3000 \
519
+ -e DATABASE_URL="postgresql://..." \
520
+ -e REDIS_HOST="redis" \
521
+ -e JWT_PRIVATE_KEY="$(cat certs/private.pem)" \
522
+ -e JWT_PUBLIC_KEY="$(cat certs/public.pem)" \
523
+ horizon-auth
524
+ ```
525
+
526
+ ### Environment Variable Best Practices
527
+
528
+ 1. **Never commit keys to Git**
529
+ 2. **Use secrets manager** (AWS Secrets Manager, Render Secrets)
530
+ 3. **Rotate keys periodically**
531
+ 4. **Use different keys** for dev/staging/production
532
+ 5. **Store keys as multiline strings** with `\n` for newlines
533
+
324
534
  ## Troubleshooting
325
535
 
326
536
  ### "Invalid or expired access token"
@@ -1,15 +1,17 @@
1
1
  export interface HorizonAuthConfig {
2
- database: {
2
+ ssoMode?: boolean;
3
+ authServiceUrl?: string;
4
+ database?: {
3
5
  url: string;
4
6
  };
5
- redis: {
7
+ redis?: {
6
8
  host: string;
7
9
  port: number;
8
10
  password?: string;
9
11
  db?: number;
10
12
  };
11
13
  jwt: {
12
- privateKey: string;
14
+ privateKey?: string;
13
15
  publicKey: string;
14
16
  accessTokenExpiry?: string;
15
17
  refreshTokenExpiry?: string;
@@ -17,6 +19,11 @@ export interface HorizonAuthConfig {
17
19
  audience?: string;
18
20
  kid?: string;
19
21
  };
22
+ cookie?: {
23
+ domain?: string;
24
+ secure?: boolean;
25
+ sameSite?: 'strict' | 'lax' | 'none';
26
+ };
20
27
  multiTenant?: {
21
28
  enabled: boolean;
22
29
  tenantIdExtractor?: 'header' | 'subdomain' | 'custom';
@@ -31,6 +31,16 @@ let HorizonAuthModule = HorizonAuthModule_1 = class HorizonAuthModule {
31
31
  useClass: jwt_auth_guard_1.JwtAuthGuard,
32
32
  });
33
33
  }
34
+ if (finalConfig.ssoMode) {
35
+ return {
36
+ module: HorizonAuthModule_1,
37
+ imports: [
38
+ auth_module_1.AuthModule,
39
+ ],
40
+ providers,
41
+ exports: ['HORIZON_AUTH_CONFIG', auth_module_1.AuthModule],
42
+ };
43
+ }
34
44
  return {
35
45
  module: HorizonAuthModule_1,
36
46
  imports: [
@@ -63,14 +73,26 @@ let HorizonAuthModule = HorizonAuthModule_1 = class HorizonAuthModule {
63
73
  };
64
74
  }
65
75
  static validateConfig(config) {
76
+ if (config.ssoMode) {
77
+ if (!config.jwt?.publicKey) {
78
+ throw new Error('HorizonAuth (SSO Mode): jwt.publicKey is required');
79
+ }
80
+ if (!config.authServiceUrl) {
81
+ throw new Error('HorizonAuth (SSO Mode): authServiceUrl is required');
82
+ }
83
+ if (!config.jwt.publicKey.includes('BEGIN')) {
84
+ throw new Error('HorizonAuth: JWT public key must be in PEM format');
85
+ }
86
+ return;
87
+ }
66
88
  if (!config.database?.url) {
67
- throw new Error('HorizonAuth: database.url is required');
89
+ throw new Error('HorizonAuth: database.url is required (or enable ssoMode)');
68
90
  }
69
91
  if (!config.redis?.host || !config.redis?.port) {
70
- throw new Error('HorizonAuth: redis.host and redis.port are required');
92
+ throw new Error('HorizonAuth: redis.host and redis.port are required (or enable ssoMode)');
71
93
  }
72
94
  if (!config.jwt?.privateKey || !config.jwt?.publicKey) {
73
- throw new Error('HorizonAuth: jwt.privateKey and jwt.publicKey are required');
95
+ throw new Error('HorizonAuth: jwt.privateKey and jwt.publicKey are required (or enable ssoMode with only publicKey)');
74
96
  }
75
97
  if (!config.jwt.privateKey.includes('BEGIN') || !config.jwt.publicKey.includes('BEGIN')) {
76
98
  throw new Error('HorizonAuth: JWT keys must be in PEM format');
@@ -79,6 +101,7 @@ let HorizonAuthModule = HorizonAuthModule_1 = class HorizonAuthModule {
79
101
  static applyDefaults(config) {
80
102
  return {
81
103
  ...config,
104
+ ssoMode: config.ssoMode || false,
82
105
  jwt: {
83
106
  ...config.jwt,
84
107
  accessTokenExpiry: config.jwt.accessTokenExpiry || '15m',
@@ -87,6 +110,11 @@ let HorizonAuthModule = HorizonAuthModule_1 = class HorizonAuthModule {
87
110
  audience: config.jwt.audience || 'horizon-api',
88
111
  kid: config.jwt.kid || 'horizon-auth-key-1',
89
112
  },
113
+ cookie: {
114
+ domain: config.cookie?.domain || config.security?.cookieDomain,
115
+ secure: config.cookie?.secure ?? config.security?.cookieSecure ?? (process.env.NODE_ENV === 'production'),
116
+ sameSite: config.cookie?.sameSite || 'lax',
117
+ },
90
118
  multiTenant: {
91
119
  enabled: config.multiTenant?.enabled || false,
92
120
  tenantIdExtractor: config.multiTenant?.tenantIdExtractor || 'header',
@@ -1 +1 @@
1
- {"version":3,"file":"horizon-auth.module.js","sourceRoot":"","sources":["../../src/lib/horizon-auth.module.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"horizon-auth.module.js","sourceRoot":"","sources":["../../src/lib/horizon-auth.module.ts"],"names":[],"mappings":"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"}