@ofeklabs/horizon-auth 0.4.1 โ 1.0.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 +175 -565
- package/dist/account/account.module.js +0 -2
- package/dist/account/account.module.js.map +1 -1
- package/dist/account/account.service.d.ts +2 -2
- package/dist/account/account.service.js +2 -2
- package/dist/account/account.service.js.map +1 -1
- package/dist/auth/auth.module.js +2 -0
- package/dist/auth/auth.module.js.map +1 -1
- package/dist/auth/auth.service.d.ts +2 -2
- package/dist/auth/auth.service.js +2 -2
- package/dist/auth/auth.service.js.map +1 -1
- package/dist/devices/device.module.js +1 -2
- package/dist/devices/device.module.js.map +1 -1
- package/dist/devices/device.service.d.ts +2 -2
- package/dist/devices/device.service.js +2 -2
- package/dist/devices/device.service.js.map +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/horizon-auth.module.d.ts +1 -1
- package/dist/lib/horizon-auth.module.js +7 -14
- package/dist/lib/horizon-auth.module.js.map +1 -1
- package/dist/push-tokens/push-token.module.js +1 -2
- package/dist/push-tokens/push-token.module.js.map +1 -1
- package/dist/push-tokens/push-token.service.d.ts +2 -2
- package/dist/push-tokens/push-token.service.js +2 -2
- package/dist/push-tokens/push-token.service.js.map +1 -1
- package/dist/social-auth/social-auth.module.js +1 -2
- package/dist/social-auth/social-auth.module.js.map +1 -1
- package/dist/social-auth/social-auth.service.d.ts +3 -3
- package/dist/social-auth/social-auth.service.js +2 -2
- package/dist/social-auth/social-auth.service.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/two-factor/two-factor.module.js +0 -2
- package/dist/two-factor/two-factor.module.js.map +1 -1
- package/dist/two-factor/two-factor.service.d.ts +2 -2
- package/dist/two-factor/two-factor.service.js +2 -2
- package/dist/two-factor/two-factor.service.js.map +1 -1
- package/dist/users/users.module.js +0 -2
- package/dist/users/users.module.js.map +1 -1
- package/dist/users/users.service.d.ts +2 -2
- package/dist/users/users.service.js +2 -2
- package/dist/users/users.service.js.map +1 -1
- package/package.json +3 -6
- package/dist/lib/horizon-auth-env.config.d.ts +0 -3
- package/dist/lib/horizon-auth-env.config.js +0 -178
- package/dist/lib/horizon-auth-env.config.js.map +0 -1
- package/dist/prisma/prisma.module.d.ts +0 -4
- package/dist/prisma/prisma.module.js +0 -33
- package/dist/prisma/prisma.module.js.map +0 -1
- package/dist/prisma/prisma.service.d.ts +0 -8
- package/dist/prisma/prisma.service.js +0 -42
- package/dist/prisma/prisma.service.js.map +0 -1
- package/prisma/migrations/20260218105110_add_enhanced_auth_features/migration.sql +0 -192
- package/prisma/migrations/migration_lock.toml +0 -3
package/README.md
CHANGED
|
@@ -1,17 +1,10 @@
|
|
|
1
1
|
# @ofeklabs/horizon-auth
|
|
2
2
|
|
|
3
|
-
Production-ready NestJS authentication module with 2026 security standards.
|
|
3
|
+
Production-ready NestJS authentication module with 2026 security standards. Deploy once, use everywhere.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Use Cases
|
|
6
6
|
|
|
7
|
-
### 1.
|
|
8
|
-
Each application has its own isolated authentication. Perfect for standalone apps.
|
|
9
|
-
|
|
10
|
-
```
|
|
11
|
-
myapp.com (App + Auth)
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
### 2. Portfolio SSO (Recommended)
|
|
7
|
+
### 1. Portfolio SSO (Recommended)
|
|
15
8
|
Deploy one auth service, use it across all your projects. Users sign in once and access everything.
|
|
16
9
|
|
|
17
10
|
```
|
|
@@ -22,7 +15,8 @@ auth.yourdomain.com (Auth Service)
|
|
|
22
15
|
โโโ project3.yourdomain.com
|
|
23
16
|
```
|
|
24
17
|
|
|
25
|
-
|
|
18
|
+
### 2. Embedded Auth
|
|
19
|
+
Each application has its own isolated authentication.
|
|
26
20
|
|
|
27
21
|
## Features
|
|
28
22
|
|
|
@@ -35,128 +29,99 @@ auth.yourdomain.com (Auth Service)
|
|
|
35
29
|
- ๐ฏ **Type-Safe**: Full TypeScript support
|
|
36
30
|
- ๐ฆ **Zero Config**: Sensible defaults, fully customizable
|
|
37
31
|
|
|
38
|
-
|
|
32
|
+
## Quick Start
|
|
39
33
|
|
|
40
|
-
|
|
41
|
-
- ๐ฑ **Device Management**: Track, list, and revoke user devices
|
|
42
|
-
- ๐ **Push Notifications**: Register and manage push tokens (FCM/APNS)
|
|
43
|
-
- ๐ค **Account Management**: Deactivate, reactivate, and delete accounts
|
|
44
|
-
- ๐ **Social Login**: Google and Facebook OAuth integration
|
|
34
|
+
### Portfolio SSO Setup (Recommended)
|
|
45
35
|
|
|
46
|
-
|
|
36
|
+
Deploy one auth service, use it across all your projects.
|
|
47
37
|
|
|
48
|
-
|
|
38
|
+
#### 1. Deploy Auth Service (One Time)
|
|
49
39
|
|
|
50
40
|
```bash
|
|
51
|
-
|
|
52
|
-
npm install
|
|
41
|
+
# Clone and deploy packages/horizon-auth to auth.yourdomain.com
|
|
42
|
+
npm install
|
|
43
|
+
npm run build
|
|
44
|
+
npm run start:prod
|
|
53
45
|
```
|
|
54
46
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
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
|
|
60
55
|
```
|
|
61
56
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
## Configuration Options
|
|
65
|
-
|
|
66
|
-
### Option 1: Environment Variables Only (Recommended โญ)
|
|
67
|
-
|
|
68
|
-
**Zero code configuration** - just set ENV variables and you're done!
|
|
57
|
+
#### 2. Use in Your Projects
|
|
69
58
|
|
|
70
|
-
|
|
59
|
+
For each project:
|
|
71
60
|
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
AUTH_MODE=full
|
|
75
|
-
DATABASE_URL=postgresql://user:password@localhost:5432/myapp
|
|
76
|
-
REDIS_HOST=localhost
|
|
77
|
-
REDIS_PORT=6379
|
|
78
|
-
JWT_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----"
|
|
79
|
-
JWT_PUBLIC_KEY="-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----"
|
|
80
|
-
|
|
81
|
-
# Optional: Enable features
|
|
82
|
-
ENABLE_2FA=true
|
|
83
|
-
ENABLE_DEVICE_MGMT=true
|
|
84
|
-
ENABLE_PUSH=true
|
|
85
|
-
ENABLE_ACCOUNT_MGMT=true
|
|
86
|
-
APP_NAME=MyApp
|
|
61
|
+
```bash
|
|
62
|
+
npm install @ofeklabs/horizon-auth
|
|
87
63
|
```
|
|
88
64
|
|
|
89
65
|
```typescript
|
|
90
66
|
// app.module.ts
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
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
|
+
},
|
|
97
77
|
})
|
|
98
|
-
export class AppModule {}
|
|
99
78
|
```
|
|
100
79
|
|
|
101
|
-
#### SSO Mode (Multiple Projects, One Auth)
|
|
102
|
-
|
|
103
|
-
**Auth Service (auth.yourdomain.com):**
|
|
104
80
|
```env
|
|
105
|
-
|
|
106
|
-
DATABASE_URL=postgresql://user:password@host:5432/auth_db
|
|
107
|
-
REDIS_HOST=redis.yourdomain.com
|
|
108
|
-
JWT_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----"
|
|
109
|
-
JWT_PUBLIC_KEY="-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----"
|
|
110
|
-
COOKIE_DOMAIN=.yourdomain.com
|
|
111
|
-
NODE_ENV=production
|
|
112
|
-
ENABLE_2FA=true
|
|
113
|
-
ENABLE_DEVICE_MGMT=true
|
|
114
|
-
APP_NAME=YourCompany
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
**Your Projects (project1.yourdomain.com, project2.yourdomain.com):**
|
|
118
|
-
```env
|
|
119
|
-
AUTH_MODE=sso
|
|
81
|
+
# .env
|
|
120
82
|
AUTH_SERVICE_URL=https://auth.yourdomain.com
|
|
121
|
-
JWT_PUBLIC_KEY
|
|
83
|
+
JWT_PUBLIC_KEY=<paste-public-key>
|
|
122
84
|
COOKIE_DOMAIN=.yourdomain.com
|
|
123
|
-
NODE_ENV=production
|
|
124
85
|
```
|
|
125
86
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
87
|
+
Deploy to:
|
|
88
|
+
- project1.yourdomain.com
|
|
89
|
+
- project2.yourdomain.com
|
|
90
|
+
- project3.yourdomain.com
|
|
129
91
|
|
|
130
|
-
|
|
131
|
-
imports: [
|
|
132
|
-
HorizonAuthModule.forRoot(), // ๐ Automatically uses SSO mode from ENV
|
|
133
|
-
],
|
|
134
|
-
})
|
|
135
|
-
export class AppModule {}
|
|
136
|
-
```
|
|
92
|
+
Users sign in once, access all projects.
|
|
137
93
|
|
|
138
|
-
|
|
94
|
+
---
|
|
139
95
|
|
|
140
|
-
|
|
96
|
+
### Embedded Auth Setup (Alternative)
|
|
141
97
|
|
|
142
|
-
|
|
98
|
+
Each application has its own authentication.
|
|
143
99
|
|
|
144
|
-
|
|
100
|
+
### 1. Install
|
|
145
101
|
|
|
146
|
-
|
|
102
|
+
```bash
|
|
103
|
+
npm install @ofeklabs/horizon-auth @prisma/client ioredis passport passport-jwt
|
|
104
|
+
npm install -D prisma
|
|
105
|
+
```
|
|
147
106
|
|
|
148
|
-
|
|
107
|
+
### 2. Generate RSA Keys
|
|
149
108
|
|
|
150
|
-
|
|
109
|
+
```bash
|
|
110
|
+
# Generate private key
|
|
111
|
+
openssl genrsa -out private.pem 2048
|
|
151
112
|
|
|
152
|
-
|
|
113
|
+
# Generate public key
|
|
114
|
+
openssl rsa -in private.pem -pubout -out public.pem
|
|
115
|
+
```
|
|
153
116
|
|
|
154
|
-
|
|
117
|
+
### 3. Configure Module
|
|
155
118
|
|
|
156
119
|
```typescript
|
|
157
120
|
// app.module.ts
|
|
158
121
|
import { Module } from '@nestjs/common';
|
|
159
122
|
import { HorizonAuthModule } from '@ofeklabs/horizon-auth';
|
|
123
|
+
import { readFileSync } from 'fs';
|
|
124
|
+
import { join } from 'path';
|
|
160
125
|
|
|
161
126
|
@Module({
|
|
162
127
|
imports: [
|
|
@@ -167,19 +132,12 @@ import { HorizonAuthModule } from '@ofeklabs/horizon-auth';
|
|
|
167
132
|
redis: {
|
|
168
133
|
host: process.env.REDIS_HOST || 'localhost',
|
|
169
134
|
port: parseInt(process.env.REDIS_PORT) || 6379,
|
|
135
|
+
password: process.env.REDIS_PASSWORD,
|
|
170
136
|
},
|
|
171
137
|
jwt: {
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
features: {
|
|
176
|
-
twoFactor: {
|
|
177
|
-
enabled: true,
|
|
178
|
-
issuer: 'YourApp',
|
|
179
|
-
},
|
|
180
|
-
deviceManagement: {
|
|
181
|
-
enabled: true,
|
|
182
|
-
},
|
|
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'),
|
|
183
141
|
},
|
|
184
142
|
}),
|
|
185
143
|
],
|
|
@@ -187,48 +145,17 @@ import { HorizonAuthModule } from '@ofeklabs/horizon-auth';
|
|
|
187
145
|
export class AppModule {}
|
|
188
146
|
```
|
|
189
147
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
```typescript
|
|
193
|
-
// app.module.ts
|
|
194
|
-
import { HorizonAuthModule } from '@ofeklabs/horizon-auth';
|
|
195
|
-
|
|
196
|
-
@Module({
|
|
197
|
-
imports: [
|
|
198
|
-
HorizonAuthModule.forRoot({
|
|
199
|
-
ssoMode: true,
|
|
200
|
-
authServiceUrl: process.env.AUTH_SERVICE_URL,
|
|
201
|
-
jwt: {
|
|
202
|
-
publicKey: process.env.JWT_PUBLIC_KEY,
|
|
203
|
-
},
|
|
204
|
-
cookie: {
|
|
205
|
-
domain: process.env.COOKIE_DOMAIN,
|
|
206
|
-
secure: process.env.NODE_ENV === 'production',
|
|
207
|
-
},
|
|
208
|
-
}),
|
|
209
|
-
],
|
|
210
|
-
})
|
|
211
|
-
export class AppModule {}
|
|
212
|
-
```
|
|
213
|
-
|
|
214
|
-
**Note:** ENV variables are still loaded automatically. Code config overrides ENV values.
|
|
215
|
-
|
|
216
|
-
---
|
|
217
|
-
|
|
218
|
-
## ๐๏ธ Database Setup
|
|
148
|
+
### 4. Set Up Database
|
|
219
149
|
|
|
220
150
|
```bash
|
|
221
|
-
# Start PostgreSQL and Redis
|
|
222
|
-
docker
|
|
223
|
-
docker run -d -p 6379:6379 redis:7-alpine
|
|
151
|
+
# Start PostgreSQL and Redis
|
|
152
|
+
docker-compose up -d
|
|
224
153
|
|
|
225
154
|
# Run Prisma migrations
|
|
226
155
|
npx prisma migrate dev
|
|
227
156
|
```
|
|
228
157
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
## ๐จ Use in Your Application
|
|
158
|
+
### 5. Use in Controllers
|
|
232
159
|
|
|
233
160
|
```typescript
|
|
234
161
|
import { Controller, Get, Post, Body, UseGuards } from '@nestjs/common';
|
|
@@ -237,6 +164,8 @@ import {
|
|
|
237
164
|
CurrentUser,
|
|
238
165
|
JwtAuthGuard,
|
|
239
166
|
Roles,
|
|
167
|
+
LoginDto,
|
|
168
|
+
RegisterDto,
|
|
240
169
|
} from '@ofeklabs/horizon-auth';
|
|
241
170
|
|
|
242
171
|
@Controller()
|
|
@@ -265,193 +194,69 @@ export class AppController {
|
|
|
265
194
|
}
|
|
266
195
|
```
|
|
267
196
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
## ๐ก API Endpoints
|
|
197
|
+
## API Endpoints
|
|
271
198
|
|
|
272
199
|
The package automatically provides these endpoints:
|
|
273
200
|
|
|
274
|
-
###
|
|
201
|
+
### Authentication
|
|
275
202
|
|
|
276
203
|
- `POST /auth/register` - Register new user
|
|
277
204
|
- `POST /auth/login` - Login with email/password
|
|
278
205
|
- `POST /auth/refresh` - Refresh access token
|
|
279
206
|
- `POST /auth/logout` - Logout and revoke tokens
|
|
280
207
|
- `GET /auth/profile` - Get current user profile
|
|
208
|
+
|
|
209
|
+
### Password Management
|
|
210
|
+
|
|
281
211
|
- `POST /auth/password-reset/request` - Request password reset
|
|
282
212
|
- `POST /auth/password-reset/complete` - Complete password reset
|
|
283
213
|
- `POST /auth/verify-email` - Verify email address
|
|
284
214
|
|
|
285
|
-
### Enterprise Features (v0.3.0+)
|
|
286
|
-
|
|
287
|
-
**Two-Factor Authentication:**
|
|
288
|
-
- `POST /auth/2fa/enable` - Enable 2FA and get QR code
|
|
289
|
-
- `POST /auth/2fa/verify` - Verify 2FA setup
|
|
290
|
-
- `POST /auth/2fa/verify-login` - Complete login with 2FA
|
|
291
|
-
- `POST /auth/2fa/disable` - Disable 2FA
|
|
292
|
-
- `POST /auth/2fa/backup-codes/regenerate` - Regenerate backup codes
|
|
293
|
-
|
|
294
|
-
**Device Management:**
|
|
295
|
-
- `GET /auth/devices` - List user's active devices
|
|
296
|
-
- `POST /auth/devices/:deviceId/revoke` - Revoke specific device
|
|
297
|
-
|
|
298
|
-
**Push Notifications:**
|
|
299
|
-
- `POST /auth/push-tokens` - Register push notification token
|
|
300
|
-
- `DELETE /auth/push-tokens/:tokenId` - Revoke push token
|
|
301
|
-
|
|
302
|
-
**Account Management:**
|
|
303
|
-
- `POST /auth/account/deactivate` - Deactivate account
|
|
304
|
-
- `POST /auth/account/reactivate` - Reactivate account
|
|
305
|
-
- `DELETE /auth/account` - Permanently delete account
|
|
306
|
-
|
|
307
|
-
**Social Login:**
|
|
308
|
-
- `POST /auth/social/google` - Google OAuth callback
|
|
309
|
-
- `POST /auth/social/facebook` - Facebook OAuth callback
|
|
310
|
-
|
|
311
215
|
### Cross-Language Support
|
|
312
216
|
|
|
313
217
|
- `GET /.well-known/jwks.json` - Public keys for JWT verification
|
|
314
218
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
## ๐ฏ How SSO Mode Works
|
|
318
|
-
|
|
319
|
-
When you deploy in SSO mode, here's what happens:
|
|
320
|
-
|
|
321
|
-
1. **Auth Service (auth.yourdomain.com):**
|
|
322
|
-
- Runs in `AUTH_MODE=full`
|
|
323
|
-
- Has database and Redis
|
|
324
|
-
- Handles login, registration, 2FA, etc.
|
|
325
|
-
- Issues JWT tokens
|
|
326
|
-
- Sets cookies for `.yourdomain.com`
|
|
327
|
-
|
|
328
|
-
2. **Your Projects (project1.yourdomain.com, project2.yourdomain.com):**
|
|
329
|
-
- Run in `AUTH_MODE=sso`
|
|
330
|
-
- No database or Redis needed
|
|
331
|
-
- Only verify JWT tokens using public key
|
|
332
|
-
- Read cookies from `.yourdomain.com`
|
|
333
|
-
- Users are automatically authenticated!
|
|
334
|
-
|
|
335
|
-
3. **User Experience:**
|
|
336
|
-
- User visits `project1.yourdomain.com`
|
|
337
|
-
- Not logged in โ Your frontend redirects to `auth.yourdomain.com/login`
|
|
338
|
-
- User logs in at auth service
|
|
339
|
-
- Cookie set for `.yourdomain.com`
|
|
340
|
-
- Redirect back to `project1.yourdomain.com`
|
|
341
|
-
- User is now logged in!
|
|
342
|
-
- User visits `project2.yourdomain.com` โ Already logged in! (same cookie)
|
|
343
|
-
|
|
344
|
-
**Important:** This package is API-only. You need to build your own login/register UI that calls the auth endpoints.
|
|
345
|
-
|
|
346
|
-
---
|
|
347
|
-
|
|
348
|
-
## ๐ง Configuration Reference
|
|
349
|
-
|
|
350
|
-
## ๐ง Configuration Reference
|
|
351
|
-
|
|
352
|
-
### Complete Configuration Interface
|
|
219
|
+
## Configuration Options
|
|
353
220
|
|
|
354
221
|
```typescript
|
|
355
222
|
interface HorizonAuthConfig {
|
|
356
|
-
//
|
|
357
|
-
|
|
358
|
-
authServiceUrl?: string; // Required when ssoMode=true
|
|
359
|
-
|
|
360
|
-
// Database (required when ssoMode=false)
|
|
361
|
-
database?: {
|
|
223
|
+
// Required
|
|
224
|
+
database: {
|
|
362
225
|
url: string;
|
|
363
226
|
};
|
|
364
|
-
|
|
365
|
-
// Redis (required when ssoMode=false)
|
|
366
|
-
redis?: {
|
|
227
|
+
redis: {
|
|
367
228
|
host: string;
|
|
368
229
|
port: number;
|
|
369
230
|
password?: string;
|
|
370
231
|
db?: number;
|
|
371
232
|
};
|
|
372
|
-
|
|
373
|
-
// JWT (always required)
|
|
374
233
|
jwt: {
|
|
375
|
-
privateKey
|
|
376
|
-
publicKey: string; //
|
|
234
|
+
privateKey: string; // RSA private key (PEM format)
|
|
235
|
+
publicKey: string; // RSA public key (PEM format)
|
|
377
236
|
accessTokenExpiry?: string; // Default: '15m'
|
|
378
237
|
refreshTokenExpiry?: string; // Default: '7d'
|
|
379
238
|
issuer?: string; // Default: 'horizon-auth'
|
|
380
239
|
audience?: string; // Default: 'horizon-api'
|
|
381
|
-
kid?: string; // Default: 'horizon-auth-key-1'
|
|
382
|
-
};
|
|
383
|
-
|
|
384
|
-
// Cookie Configuration
|
|
385
|
-
cookie?: {
|
|
386
|
-
domain?: string; // e.g., '.yourdomain.com' for SSO
|
|
387
|
-
secure?: boolean; // Default: true in production
|
|
388
|
-
sameSite?: 'strict' | 'lax' | 'none'; // Default: 'lax'
|
|
389
240
|
};
|
|
390
|
-
|
|
391
|
-
//
|
|
241
|
+
|
|
242
|
+
// Optional
|
|
392
243
|
multiTenant?: {
|
|
393
244
|
enabled: boolean;
|
|
394
245
|
tenantIdExtractor?: 'header' | 'subdomain' | 'custom';
|
|
395
246
|
defaultTenantId?: string;
|
|
396
247
|
};
|
|
397
|
-
|
|
398
|
-
// Rate Limiting
|
|
399
248
|
rateLimit?: {
|
|
400
249
|
login?: { limit: number; ttl: number };
|
|
401
250
|
register?: { limit: number; ttl: number };
|
|
402
251
|
passwordReset?: { limit: number; ttl: number };
|
|
403
252
|
};
|
|
404
|
-
|
|
405
|
-
// Email Configuration
|
|
406
|
-
email?: {
|
|
407
|
-
provider: 'resend' | 'sendgrid' | 'custom';
|
|
408
|
-
apiKey?: string;
|
|
409
|
-
from?: string;
|
|
410
|
-
};
|
|
411
|
-
|
|
412
|
-
// Global Guards
|
|
413
253
|
guards?: {
|
|
414
254
|
applyJwtGuardGlobally?: boolean;
|
|
415
255
|
};
|
|
416
|
-
|
|
417
|
-
// Enterprise Features
|
|
418
|
-
features?: {
|
|
419
|
-
twoFactor?: {
|
|
420
|
-
enabled: boolean;
|
|
421
|
-
issuer?: string; // Shows in authenticator apps
|
|
422
|
-
};
|
|
423
|
-
deviceManagement?: {
|
|
424
|
-
enabled: boolean;
|
|
425
|
-
maxDevicesPerUser?: number;
|
|
426
|
-
};
|
|
427
|
-
pushNotifications?: {
|
|
428
|
-
enabled: boolean;
|
|
429
|
-
};
|
|
430
|
-
accountManagement?: {
|
|
431
|
-
enabled: boolean;
|
|
432
|
-
allowReactivation?: boolean;
|
|
433
|
-
};
|
|
434
|
-
socialLogin?: {
|
|
435
|
-
google?: {
|
|
436
|
-
clientId: string;
|
|
437
|
-
clientSecret: string;
|
|
438
|
-
callbackUrl: string;
|
|
439
|
-
};
|
|
440
|
-
facebook?: {
|
|
441
|
-
appId: string;
|
|
442
|
-
appSecret: string;
|
|
443
|
-
callbackUrl: string;
|
|
444
|
-
};
|
|
445
|
-
};
|
|
446
|
-
};
|
|
447
256
|
}
|
|
448
257
|
```
|
|
449
258
|
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
---
|
|
453
|
-
|
|
454
|
-
## ๐ญ Decorators
|
|
259
|
+
## Decorators
|
|
455
260
|
|
|
456
261
|
### @Public()
|
|
457
262
|
Mark routes as publicly accessible (skip authentication)
|
|
@@ -495,113 +300,105 @@ getTenantData(@CurrentTenant() tenantId: string) {
|
|
|
495
300
|
}
|
|
496
301
|
```
|
|
497
302
|
|
|
498
|
-
##
|
|
499
|
-
|
|
500
|
-
### Two-Factor Authentication
|
|
303
|
+
## Multi-Tenant Configuration
|
|
501
304
|
|
|
502
305
|
```typescript
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
// Display QR code to user (qrCode is a data URL)
|
|
511
|
-
// User scans with Google Authenticator or Authy
|
|
512
|
-
|
|
513
|
-
// Verify setup with code from authenticator
|
|
514
|
-
await fetch('/auth/2fa/verify', {
|
|
515
|
-
method: 'POST',
|
|
516
|
-
headers: {
|
|
517
|
-
Authorization: `Bearer ${accessToken}`,
|
|
518
|
-
'Content-Type': 'application/json',
|
|
306
|
+
HorizonAuthModule.forRoot({
|
|
307
|
+
// ... other config
|
|
308
|
+
multiTenant: {
|
|
309
|
+
enabled: true,
|
|
310
|
+
tenantIdExtractor: 'header', // or 'subdomain' or 'custom'
|
|
311
|
+
defaultTenantId: 'default',
|
|
519
312
|
},
|
|
520
|
-
body: JSON.stringify({ code: '123456' }),
|
|
521
313
|
});
|
|
314
|
+
```
|
|
522
315
|
|
|
523
|
-
|
|
524
|
-
const loginResponse = await fetch('/auth/login', {
|
|
525
|
-
method: 'POST',
|
|
526
|
-
body: JSON.stringify({ email, password }),
|
|
527
|
-
});
|
|
316
|
+
## Dev SSO Mode
|
|
528
317
|
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
318
|
+
For local development with multiple microservices:
|
|
319
|
+
|
|
320
|
+
```yaml
|
|
321
|
+
# docker-compose.dev-sso.yml
|
|
322
|
+
version: '3.8'
|
|
323
|
+
services:
|
|
324
|
+
auth-service:
|
|
325
|
+
build: .
|
|
326
|
+
ports:
|
|
327
|
+
- '3000:3000'
|
|
328
|
+
environment:
|
|
329
|
+
COOKIE_DOMAIN: '.localhost'
|
|
330
|
+
REDIS_HOST: redis
|
|
331
|
+
depends_on:
|
|
332
|
+
- postgres
|
|
333
|
+
- redis
|
|
539
334
|
```
|
|
540
335
|
|
|
541
|
-
|
|
336
|
+
All `*.localhost:3000` apps will share the same authentication session.
|
|
542
337
|
|
|
543
|
-
|
|
544
|
-
// List user's devices (automatically tracked on login)
|
|
545
|
-
const devices = await fetch('/auth/devices', {
|
|
546
|
-
headers: { Authorization: `Bearer ${accessToken}` },
|
|
547
|
-
}).then(r => r.json());
|
|
548
|
-
|
|
549
|
-
// Revoke a specific device
|
|
550
|
-
await fetch(`/auth/devices/${deviceId}/revoke`, {
|
|
551
|
-
method: 'POST',
|
|
552
|
-
headers: { Authorization: `Bearer ${accessToken}` },
|
|
553
|
-
});
|
|
554
|
-
```
|
|
338
|
+
## Cross-Language Token Verification
|
|
555
339
|
|
|
556
|
-
###
|
|
340
|
+
### C# Example
|
|
557
341
|
|
|
558
|
-
```
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
342
|
+
```csharp
|
|
343
|
+
using Microsoft.IdentityModel.Tokens;
|
|
344
|
+
using System.IdentityModel.Tokens.Jwt;
|
|
345
|
+
|
|
346
|
+
var jwks = await httpClient.GetStringAsync("http://auth-service/.well-known/jwks.json");
|
|
347
|
+
var keys = JsonConvert.DeserializeObject<JsonWebKeySet>(jwks);
|
|
348
|
+
|
|
349
|
+
var tokenHandler = new JwtSecurityTokenHandler();
|
|
350
|
+
var validationParameters = new TokenValidationParameters
|
|
351
|
+
{
|
|
352
|
+
ValidateIssuerSigningKey = true,
|
|
353
|
+
IssuerSigningKeys = keys.Keys,
|
|
354
|
+
ValidateIssuer = true,
|
|
355
|
+
ValidIssuer = "horizon-auth",
|
|
356
|
+
ValidateAudience = true,
|
|
357
|
+
ValidAudience = "horizon-api"
|
|
358
|
+
};
|
|
359
|
+
|
|
360
|
+
var principal = tokenHandler.ValidateToken(token, validationParameters, out var validatedToken);
|
|
572
361
|
```
|
|
573
362
|
|
|
574
|
-
###
|
|
363
|
+
### Python Example
|
|
575
364
|
|
|
576
|
-
```
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
method: 'POST',
|
|
580
|
-
headers: {
|
|
581
|
-
Authorization: `Bearer ${accessToken}`,
|
|
582
|
-
'Content-Type': 'application/json',
|
|
583
|
-
},
|
|
584
|
-
body: JSON.stringify({
|
|
585
|
-
reason: 'Taking a break',
|
|
586
|
-
}),
|
|
587
|
-
});
|
|
365
|
+
```python
|
|
366
|
+
import jwt
|
|
367
|
+
import requests
|
|
588
368
|
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
body: JSON.stringify({ email, password }),
|
|
593
|
-
});
|
|
369
|
+
# Fetch JWKS
|
|
370
|
+
jwks_url = "http://auth-service/.well-known/jwks.json"
|
|
371
|
+
jwks = requests.get(jwks_url).json()
|
|
594
372
|
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
373
|
+
# Verify token
|
|
374
|
+
token = "your-jwt-token"
|
|
375
|
+
decoded = jwt.decode(
|
|
376
|
+
token,
|
|
377
|
+
jwks,
|
|
378
|
+
algorithms=["RS256"],
|
|
379
|
+
issuer="horizon-auth",
|
|
380
|
+
audience="horizon-api"
|
|
381
|
+
)
|
|
600
382
|
```
|
|
601
383
|
|
|
602
|
-
|
|
384
|
+
## Security Best Practices
|
|
385
|
+
|
|
386
|
+
1. **Always use HTTPS in production**
|
|
387
|
+
2. **Store RSA keys securely** (environment variables, secrets manager)
|
|
388
|
+
3. **Enable rate limiting** to prevent brute force attacks
|
|
389
|
+
4. **Monitor security events** (failed logins, token reuse)
|
|
390
|
+
5. **Rotate JWT keys periodically**
|
|
391
|
+
6. **Use strong Redis passwords** in production
|
|
603
392
|
|
|
604
|
-
##
|
|
393
|
+
## Environment Variables
|
|
394
|
+
|
|
395
|
+
```env
|
|
396
|
+
# Database
|
|
397
|
+
DATABASE_URL=postgresql://user:password@localhost:5432/horizon_auth
|
|
398
|
+
|
|
399
|
+
# Redis
|
|
400
|
+
REDIS_HOST=localhost
|
|
401
|
+
REDIS_PORT=6379
|
|
605
402
|
REDIS_PASSWORD=your_redis_password
|
|
606
403
|
|
|
607
404
|
# JWT Keys (for production - use multiline env vars)
|
|
@@ -751,209 +548,22 @@ docker run -p 3000:3000 \
|
|
|
751
548
|
- All user tokens have been revoked for security
|
|
752
549
|
- User needs to login again
|
|
753
550
|
|
|
754
|
-
|
|
755
|
-
- Push tokens require a valid deviceId
|
|
756
|
-
- Devices are created automatically on login (not registration)
|
|
757
|
-
- Login first, then get device list, then register push token
|
|
758
|
-
|
|
759
|
-
### "Feature disabled" error
|
|
760
|
-
- The feature you're trying to use is not enabled in configuration
|
|
761
|
-
- Enable it in `HorizonAuthModule.forRoot({ features: { ... } })`
|
|
762
|
-
|
|
763
|
-
## Testing Status
|
|
764
|
-
|
|
765
|
-
**โ
Fully Tested:**
|
|
766
|
-
- User registration and login
|
|
767
|
-
- JWT token generation and validation
|
|
768
|
-
- Refresh token rotation
|
|
769
|
-
- 2FA setup (QR code generation)
|
|
770
|
-
- Account deactivation/reactivation
|
|
771
|
-
- Login protection for deactivated accounts
|
|
772
|
-
|
|
773
|
-
**โ ๏ธ Requires Manual Testing:**
|
|
774
|
-
- 2FA login flow (requires actual authenticator app)
|
|
775
|
-
- Device tracking (automatic on login)
|
|
776
|
-
- Push token registration (requires valid device)
|
|
777
|
-
- Social login (requires OAuth credentials from Google/Facebook)
|
|
778
|
-
- Backup codes usage during login
|
|
779
|
-
|
|
780
|
-
## ๐ Cross-Platform Support
|
|
781
|
-
|
|
782
|
-
**Works with ANY backend language!** Your auth service issues JWT tokens that can be verified by:
|
|
783
|
-
- โ
NestJS (use package in SSO mode)
|
|
784
|
-
- โ
.NET / C# (JWT Bearer Auth)
|
|
785
|
-
- โ
Python (PyJWT)
|
|
786
|
-
- โ
Go (golang-jwt)
|
|
787
|
-
- โ
Java / Spring Boot (OAuth2 Resource Server)
|
|
788
|
-
- โ
PHP (Firebase JWT)
|
|
789
|
-
- โ
Any language with JWT support!
|
|
790
|
-
|
|
791
|
-
**๐ See [CROSS-PLATFORM-INTEGRATION.md](https://github.com/OfekItzhaki/horizon-auth-platform/blob/main/CROSS-PLATFORM-INTEGRATION.md) for complete integration guides with code examples.**
|
|
792
|
-
|
|
793
|
-
---
|
|
794
|
-
|
|
795
|
-
## ๐ Cross-Language Token Verification
|
|
796
|
-
|
|
797
|
-
Your other services (in any language) can verify tokens using the JWKS endpoint:
|
|
798
|
-
|
|
799
|
-
### C# Example
|
|
800
|
-
|
|
801
|
-
```csharp
|
|
802
|
-
using Microsoft.IdentityModel.Tokens;
|
|
803
|
-
using System.IdentityModel.Tokens.Jwt;
|
|
804
|
-
|
|
805
|
-
var jwks = await httpClient.GetStringAsync("https://auth.yourdomain.com/.well-known/jwks.json");
|
|
806
|
-
var keys = JsonConvert.DeserializeObject<JsonWebKeySet>(jwks);
|
|
807
|
-
|
|
808
|
-
var tokenHandler = new JwtSecurityTokenHandler();
|
|
809
|
-
var validationParameters = new TokenValidationParameters
|
|
810
|
-
{
|
|
811
|
-
ValidateIssuerSigningKey = true,
|
|
812
|
-
IssuerSigningKeys = keys.Keys,
|
|
813
|
-
ValidateIssuer = true,
|
|
814
|
-
ValidIssuer = "horizon-auth",
|
|
815
|
-
ValidateAudience = true,
|
|
816
|
-
ValidAudience = "horizon-api"
|
|
817
|
-
};
|
|
818
|
-
|
|
819
|
-
var principal = tokenHandler.ValidateToken(token, validationParameters, out var validatedToken);
|
|
820
|
-
```
|
|
821
|
-
|
|
822
|
-
### Python Example
|
|
823
|
-
|
|
824
|
-
```python
|
|
825
|
-
import jwt
|
|
826
|
-
import requests
|
|
827
|
-
|
|
828
|
-
# Fetch JWKS
|
|
829
|
-
jwks_url = "https://auth.yourdomain.com/.well-known/jwks.json"
|
|
830
|
-
jwks = requests.get(jwks_url).json()
|
|
831
|
-
|
|
832
|
-
# Verify token
|
|
833
|
-
token = "your-jwt-token"
|
|
834
|
-
decoded = jwt.decode(
|
|
835
|
-
token,
|
|
836
|
-
jwks,
|
|
837
|
-
algorithms=["RS256"],
|
|
838
|
-
issuer="horizon-auth",
|
|
839
|
-
audience="horizon-api"
|
|
840
|
-
)
|
|
841
|
-
```
|
|
842
|
-
|
|
843
|
-
---
|
|
844
|
-
|
|
845
|
-
## ๐ Troubleshooting
|
|
846
|
-
|
|
847
|
-
### "AUTH_SERVICE_URL is required when AUTH_MODE=sso"
|
|
848
|
-
Set `AUTH_SERVICE_URL` in your ENV file when using SSO mode.
|
|
849
|
-
|
|
850
|
-
### "JWT_PRIVATE_KEY is required when AUTH_MODE=full"
|
|
851
|
-
Make sure you've set `JWT_PRIVATE_KEY` when running in full mode (auth service).
|
|
852
|
-
|
|
853
|
-
### "Invalid or expired access token"
|
|
854
|
-
- Check that your JWT keys are correctly configured
|
|
855
|
-
- Verify token hasn't expired (default 15 minutes)
|
|
856
|
-
- Ensure token isn't blacklisted in Redis
|
|
857
|
-
|
|
858
|
-
### "Redis connection error"
|
|
859
|
-
- Verify Redis is running: `docker ps` or check your cloud Redis service
|
|
860
|
-
- Check Redis connection settings in ENV
|
|
861
|
-
- Test connection: `redis-cli ping`
|
|
862
|
-
|
|
863
|
-
### "Token reuse detected"
|
|
864
|
-
- This is a security feature - someone tried to reuse a revoked refresh token
|
|
865
|
-
- All user tokens have been revoked for security
|
|
866
|
-
- User needs to login again
|
|
867
|
-
|
|
868
|
-
### "Device ID required for push tokens"
|
|
869
|
-
- Push tokens require a valid deviceId
|
|
870
|
-
- Devices are created automatically on login (not registration)
|
|
871
|
-
- Login first, then get device list, then register push token
|
|
551
|
+
## Migration from Existing Auth
|
|
872
552
|
|
|
873
|
-
|
|
874
|
-
-
|
|
875
|
-
-
|
|
553
|
+
See [MIGRATION.md](./MIGRATION.md) for guides on:
|
|
554
|
+
- Migrating from bcrypt to Argon2id
|
|
555
|
+
- Migrating from HS256 to RS256
|
|
556
|
+
- Database schema migration
|
|
876
557
|
|
|
877
|
-
|
|
878
|
-
- Make sure `COOKIE_DOMAIN` starts with a dot: `.yourdomain.com`
|
|
879
|
-
- Verify `COOKIE_SECURE=true` in production (requires HTTPS)
|
|
880
|
-
- Check that all apps use the same cookie domain
|
|
881
|
-
|
|
882
|
-
---
|
|
883
|
-
|
|
884
|
-
## ๐ Documentation
|
|
885
|
-
|
|
886
|
-
- **[ENV-CONFIGURATION.md](https://github.com/OfekItzhaki/horizon-auth-platform/blob/main/ENV-CONFIGURATION.md)** - Complete environment variable reference
|
|
887
|
-
- **[DEPLOYMENT-EXAMPLES.md](https://github.com/OfekItzhaki/horizon-auth-platform/blob/main/DEPLOYMENT-EXAMPLES.md)** - Real-world deployment scenarios
|
|
888
|
-
- **[CROSS-PLATFORM-INTEGRATION.md](https://github.com/OfekItzhaki/horizon-auth-platform/blob/main/CROSS-PLATFORM-INTEGRATION.md)** - Integration with .NET, Python, Go, Java, PHP
|
|
889
|
-
- **[GitHub Repository](https://github.com/OfekItzhaki/horizon-auth-platform)** - Source code and issues
|
|
890
|
-
|
|
891
|
-
---
|
|
892
|
-
|
|
893
|
-
## ๐งช Testing Status
|
|
894
|
-
|
|
895
|
-
**โ
Fully Tested:**
|
|
896
|
-
- User registration and login
|
|
897
|
-
- JWT token generation and validation
|
|
898
|
-
- Refresh token rotation
|
|
899
|
-
- 2FA setup (QR code generation)
|
|
900
|
-
- Account deactivation/reactivation
|
|
901
|
-
- Login protection for deactivated accounts
|
|
902
|
-
- SSO mode token verification
|
|
903
|
-
|
|
904
|
-
**โ ๏ธ Requires Manual Testing:**
|
|
905
|
-
- 2FA login flow (requires actual authenticator app)
|
|
906
|
-
- Device tracking (automatic on login)
|
|
907
|
-
- Push token registration (requires valid device)
|
|
908
|
-
- Social login (requires OAuth credentials from Google/Facebook)
|
|
909
|
-
- Backup codes usage during login
|
|
910
|
-
|
|
911
|
-
---
|
|
912
|
-
|
|
913
|
-
## ๐ฆ What's New
|
|
914
|
-
|
|
915
|
-
### v0.4.1 (Latest)
|
|
916
|
-
- ๐ **Cross-platform integration guide** - Complete examples for .NET, Python, Go, Java, PHP
|
|
917
|
-
- ๐ Enhanced README with cross-platform support section
|
|
918
|
-
- ๐ JWKS endpoint documentation for polyglot architectures
|
|
919
|
-
|
|
920
|
-
### v0.4.0
|
|
921
|
-
- โจ **ENV-based configuration** - Zero code changes needed!
|
|
922
|
-
- โจ **Flexible deployment** - Same package for embedded and SSO modes
|
|
923
|
-
- ๐ Complete ENV variable documentation
|
|
924
|
-
- ๐ Real-world deployment examples
|
|
925
|
-
- ๐ง Improved configuration merging
|
|
926
|
-
|
|
927
|
-
### v0.3.0
|
|
928
|
-
- โจ Two-Factor Authentication (TOTP)
|
|
929
|
-
- โจ Device Management
|
|
930
|
-
- โจ Push Notifications
|
|
931
|
-
- โจ Account Management
|
|
932
|
-
- โจ Social Login (Google, Facebook)
|
|
933
|
-
|
|
934
|
-
### v0.2.1
|
|
935
|
-
- ๐ Fixed SSO mode JWT strategy
|
|
936
|
-
- ๐ง Dynamic module configuration
|
|
937
|
-
|
|
938
|
-
---
|
|
939
|
-
|
|
940
|
-
## ๐ License
|
|
558
|
+
## License
|
|
941
559
|
|
|
942
560
|
MIT
|
|
943
561
|
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
## ๐ค Support
|
|
947
|
-
|
|
948
|
-
- **Issues:** [GitHub Issues](https://github.com/OfekItzhaki/horizon-auth-platform/issues)
|
|
949
|
-
- **Discussions:** [GitHub Discussions](https://github.com/OfekItzhaki/horizon-auth-platform/discussions)
|
|
562
|
+
## Support
|
|
950
563
|
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
## ๐จโ๐ป Author
|
|
564
|
+
- GitHub Issues: https://github.com/OfekItzhaki/horizon-auth-platform/issues
|
|
565
|
+
- Documentation: https://github.com/OfekItzhaki/horizon-auth-platform
|
|
954
566
|
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
---
|
|
567
|
+
## Credits
|
|
958
568
|
|
|
959
|
-
|
|
569
|
+
Created by Ofek Itzhaki
|