@intelicity/gates-sdk 0.1.5 → 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 +110 -292
- package/dist/auth/middleware.d.ts +10 -1
- package/dist/auth/middleware.d.ts.map +1 -1
- package/dist/auth/middleware.js +31 -40
- package/dist/errors/error.d.ts +21 -13
- package/dist/errors/error.d.ts.map +1 -1
- package/dist/errors/error.js +51 -15
- package/dist/index.d.ts +5 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -3
- package/dist/models/user.d.ts +6 -7
- package/dist/models/user.d.ts.map +1 -1
- package/dist/services/admin-service.d.ts +26 -0
- package/dist/services/admin-service.d.ts.map +1 -0
- package/dist/services/admin-service.js +92 -0
- package/dist/services/auth-service.d.ts +4 -7
- package/dist/services/auth-service.d.ts.map +1 -1
- package/dist/services/auth-service.js +69 -54
- package/dist/services/client-auth.d.ts +22 -0
- package/dist/services/client-auth.d.ts.map +1 -0
- package/dist/services/client-auth.js +75 -0
- package/dist/services/user-service.d.ts +2 -2
- package/dist/services/user-service.d.ts.map +1 -1
- package/dist/services/user-service.js +43 -23
- package/package.json +5 -2
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Gates SDK
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Node.js SDK for the Gates authentication system (AWS Cognito). Provides JWT token verification, group-based access control, admin user management, and framework-agnostic middleware.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -10,364 +10,182 @@ npm install @intelicity/gates-sdk
|
|
|
10
10
|
|
|
11
11
|
## Features
|
|
12
12
|
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
13
|
+
- JWT verification for both access and id tokens
|
|
14
|
+
- Admin user management (create + assign to client/group)
|
|
15
|
+
- Framework-agnostic middleware (works with Fastify, Express, etc.)
|
|
16
|
+
- Built-in JWKS caching (1h TTL)
|
|
17
|
+
- Group-based access control (Cognito Groups)
|
|
18
|
+
- Comprehensive error hierarchy
|
|
19
19
|
|
|
20
20
|
## Usage
|
|
21
21
|
|
|
22
|
-
###
|
|
23
|
-
|
|
24
|
-
The `AuthService` provides JWT token verification with AWS Cognito:
|
|
22
|
+
### Token Verification
|
|
25
23
|
|
|
26
24
|
```typescript
|
|
27
25
|
import { AuthService } from "@intelicity/gates-sdk";
|
|
28
26
|
|
|
29
|
-
const
|
|
30
|
-
"sa-east-1",
|
|
27
|
+
const auth = new AuthService(
|
|
28
|
+
"sa-east-1", // AWS region
|
|
31
29
|
"sa-east-1_xxxxxxxxx", // User Pool ID
|
|
32
|
-
"your-client-id"
|
|
33
|
-
["admin", "user"] // Optional: required groups
|
|
30
|
+
"your-client-id" // Cognito App Client ID
|
|
34
31
|
);
|
|
35
32
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
const user = await authService.verifyToken(token);
|
|
39
|
-
console.log("Authenticated user:", user);
|
|
40
|
-
|
|
41
|
-
// Check group membership
|
|
42
|
-
const isAdmin = authService.isMemberOf(user.groups || []);
|
|
43
|
-
console.log("Has required group:", isAdmin);
|
|
44
|
-
} catch (error) {
|
|
45
|
-
console.error("Authentication failed:", error.message);
|
|
46
|
-
}
|
|
33
|
+
const user = await auth.verifyToken(accessToken);
|
|
34
|
+
// user.user_id, user.groups, user.token_use, user.email?, user.name?
|
|
47
35
|
```
|
|
48
36
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
The `UserService` provides user management capabilities:
|
|
37
|
+
Supports both `access_token` (validates `client_id` claim) and `id_token` (validates `aud` claim). The `token_use` field on the returned user indicates which type was verified.
|
|
52
38
|
|
|
53
|
-
|
|
54
|
-
import { UserService } from "@intelicity/gates-sdk";
|
|
55
|
-
|
|
56
|
-
const userService = new UserService(
|
|
57
|
-
"https://api.example.com", // Backend API URL
|
|
58
|
-
"your-system-name" // System identifier
|
|
59
|
-
);
|
|
39
|
+
### Middleware
|
|
60
40
|
|
|
61
|
-
|
|
62
|
-
try {
|
|
63
|
-
const users = await userService.getAllUsers(idToken);
|
|
64
|
-
console.log("Users:", users.profiles);
|
|
65
|
-
console.log("Total:", users.total);
|
|
66
|
-
} catch (error) {
|
|
67
|
-
console.error("Failed to fetch users:", error.message);
|
|
68
|
-
}
|
|
41
|
+
Framework-agnostic functions for request authentication:
|
|
69
42
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
43
|
+
```typescript
|
|
44
|
+
import { handleAuth, AuthService } from "@intelicity/gates-sdk";
|
|
45
|
+
|
|
46
|
+
const service = new AuthService(region, userPoolId, clientId);
|
|
47
|
+
|
|
48
|
+
// Fastify
|
|
49
|
+
app.addHook("preHandler", async (req) => {
|
|
50
|
+
req.user = await handleAuth(req.headers.authorization, {
|
|
51
|
+
service,
|
|
52
|
+
requiredGroups: "GAIA",
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
// Express
|
|
57
|
+
app.use(async (req, res, next) => {
|
|
58
|
+
try {
|
|
59
|
+
req.user = await handleAuth(req.headers.authorization, {
|
|
60
|
+
service,
|
|
61
|
+
requiredGroups: "GAIA",
|
|
62
|
+
});
|
|
63
|
+
next();
|
|
64
|
+
} catch (e) { next(e); }
|
|
65
|
+
});
|
|
77
66
|
```
|
|
78
67
|
|
|
79
|
-
|
|
68
|
+
Individual functions are also available:
|
|
80
69
|
|
|
81
70
|
```typescript
|
|
82
|
-
import {
|
|
83
|
-
|
|
84
|
-
class MyApplication {
|
|
85
|
-
private authService: AuthService;
|
|
86
|
-
private userService: UserService;
|
|
87
|
-
|
|
88
|
-
constructor() {
|
|
89
|
-
this.authService = new AuthService(
|
|
90
|
-
process.env.AWS_REGION!,
|
|
91
|
-
process.env.COGNITO_USER_POOL_ID!,
|
|
92
|
-
process.env.COGNITO_CLIENT_ID!,
|
|
93
|
-
["admin"] // Only admins can access
|
|
94
|
-
);
|
|
95
|
-
|
|
96
|
-
this.userService = new UserService(
|
|
97
|
-
process.env.BACKEND_URL!,
|
|
98
|
-
process.env.SYSTEM_NAME!
|
|
99
|
-
);
|
|
100
|
-
}
|
|
71
|
+
import { extractToken, authenticate, authorize } from "@intelicity/gates-sdk";
|
|
101
72
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
const user = await this.authService.verifyToken(authToken);
|
|
106
|
-
console.log(`User ${user.name} authenticated successfully`);
|
|
107
|
-
|
|
108
|
-
// 2. Get user list if authorized
|
|
109
|
-
const users = await this.userService.getAllUsers(authToken);
|
|
110
|
-
|
|
111
|
-
return {
|
|
112
|
-
currentUser: user,
|
|
113
|
-
allUsers: users.profiles,
|
|
114
|
-
total: users.total,
|
|
115
|
-
};
|
|
116
|
-
} catch (error) {
|
|
117
|
-
throw new Error(`Operation failed: ${error.message}`);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
}
|
|
73
|
+
const token = extractToken(req.headers.authorization); // Bearer token extraction
|
|
74
|
+
const user = await authenticate(token, service); // JWT verification
|
|
75
|
+
authorize(user, ["GAIA", "RECAPE"]); // Group check (throws if unauthorized)
|
|
121
76
|
```
|
|
122
77
|
|
|
123
78
|
### Error Handling
|
|
124
79
|
|
|
125
|
-
The SDK provides custom error classes for better error handling:
|
|
126
|
-
|
|
127
80
|
```typescript
|
|
128
81
|
import {
|
|
129
|
-
AuthService,
|
|
130
|
-
UserService,
|
|
131
|
-
AuthenticationError,
|
|
132
82
|
TokenExpiredError,
|
|
133
83
|
InvalidTokenError,
|
|
134
|
-
|
|
84
|
+
UnauthorizedGroupError,
|
|
85
|
+
GatesError,
|
|
135
86
|
} from "@intelicity/gates-sdk";
|
|
136
87
|
|
|
137
|
-
const authService = new AuthService(region, userPoolId, audience);
|
|
138
|
-
|
|
139
88
|
try {
|
|
140
|
-
const user = await
|
|
89
|
+
const user = await auth.verifyToken(token);
|
|
141
90
|
} catch (error) {
|
|
142
91
|
if (error instanceof TokenExpiredError) {
|
|
143
|
-
|
|
92
|
+
// error.code === "TOKEN_EXPIRED"
|
|
144
93
|
} else if (error instanceof InvalidTokenError) {
|
|
145
|
-
|
|
146
|
-
} else if (error instanceof
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// Error handling with User Service
|
|
154
|
-
try {
|
|
155
|
-
const users = await userService.getAllUsers(token);
|
|
156
|
-
} catch (error) {
|
|
157
|
-
if (error.message.includes("HTTP 401")) {
|
|
158
|
-
console.error("Unauthorized - check your token");
|
|
159
|
-
} else if (error.message.includes("HTTP 403")) {
|
|
160
|
-
console.error("Forbidden - insufficient permissions");
|
|
161
|
-
} else {
|
|
162
|
-
console.error("Failed to fetch users:", error.message);
|
|
94
|
+
// error.code === "INVALID_TOKEN"
|
|
95
|
+
} else if (error instanceof UnauthorizedGroupError) {
|
|
96
|
+
// error.code === "UNAUTHORIZED_GROUP"
|
|
97
|
+
// error.requiredGroups: string[]
|
|
98
|
+
} else if (error instanceof GatesError) {
|
|
99
|
+
// error.code, error.message
|
|
163
100
|
}
|
|
164
101
|
}
|
|
165
102
|
```
|
|
166
103
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
### `AuthService`
|
|
170
|
-
|
|
171
|
-
Main service for JWT token verification with AWS Cognito.
|
|
104
|
+
### Admin Service (User Management)
|
|
172
105
|
|
|
173
|
-
|
|
106
|
+
For creating users and managing system access (requires admin id_token):
|
|
174
107
|
|
|
175
108
|
```typescript
|
|
176
|
-
|
|
109
|
+
import { GatesAdminService } from "@intelicity/gates-sdk";
|
|
110
|
+
|
|
111
|
+
const admin = new GatesAdminService({
|
|
112
|
+
baseUrl: "https://abc123.execute-api.sa-east-1.amazonaws.com/prod",
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
// Create a new user and add to a client (group)
|
|
116
|
+
// Internally calls POST /create-user then PUT /update-user
|
|
117
|
+
const { sub } = await admin.createUser(adminIdToken, {
|
|
118
|
+
email: "newuser@company.com",
|
|
119
|
+
name: "New User",
|
|
120
|
+
role: "CLIENT_USER",
|
|
121
|
+
client: "GAIA",
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
// Later: add/remove user access to other systems
|
|
125
|
+
await admin.updateUser(adminIdToken, {
|
|
126
|
+
user_id: sub,
|
|
127
|
+
clients_to_add: ["RECAPE"],
|
|
128
|
+
clients_to_remove: ["INFORMS"],
|
|
129
|
+
});
|
|
177
130
|
```
|
|
178
131
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
- `region` (string): AWS region (e.g., 'sa-east-1')
|
|
182
|
-
- `userPoolId` (string): Cognito User Pool ID
|
|
183
|
-
- `audience` (string): Expected audience claim (client ID)
|
|
184
|
-
- `requiredGroup` (string | string[], optional): Required Cognito groups
|
|
185
|
-
|
|
186
|
-
#### Methods
|
|
187
|
-
|
|
188
|
-
##### `verifyToken(token: string): Promise<GatesUser>`
|
|
189
|
-
|
|
190
|
-
Verifies a JWT token and returns the authenticated user.
|
|
191
|
-
|
|
192
|
-
##### `isMemberOf(groups: string[]): boolean`
|
|
193
|
-
|
|
194
|
-
Checks if the user groups match the required groups.
|
|
195
|
-
|
|
196
|
-
### `UserService`
|
|
197
|
-
|
|
198
|
-
Service for managing users through a backend API.
|
|
132
|
+
## API Reference
|
|
199
133
|
|
|
200
|
-
|
|
134
|
+
### `AuthService`
|
|
201
135
|
|
|
202
136
|
```typescript
|
|
203
|
-
new
|
|
137
|
+
new AuthService(region: string, userPoolId: string, clientId: string)
|
|
204
138
|
```
|
|
205
139
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
- `baseUrl` (string): Backend API base URL
|
|
209
|
-
- `system` (string): System identifier
|
|
210
|
-
|
|
211
|
-
#### Methods
|
|
212
|
-
|
|
213
|
-
##### `getAllUsers(idToken: string): Promise<UserListResponse>`
|
|
214
|
-
|
|
215
|
-
Retrieves all users from the system.
|
|
216
|
-
|
|
217
|
-
##### `getUserById(idToken: string, userId: string): Promise<Profile>`
|
|
218
|
-
|
|
219
|
-
Retrieves a specific user by ID.
|
|
220
|
-
|
|
221
|
-
### Types
|
|
222
|
-
|
|
223
|
-
#### `GatesUser`
|
|
224
|
-
|
|
225
|
-
```typescript
|
|
226
|
-
type GatesUser = {
|
|
227
|
-
user_id: string; // Mapped from 'sub' claim
|
|
228
|
-
email: string; // User email
|
|
229
|
-
name: string; // User display name
|
|
230
|
-
role: string; // Mapped from 'custom:general_role'
|
|
231
|
-
exp: number; // Token expiration timestamp
|
|
232
|
-
iat: number; // Token issued at timestamp
|
|
233
|
-
};
|
|
234
|
-
```
|
|
140
|
+
- `verifyToken(token: string): Promise<GatesUser>` — Verifies JWT, returns user
|
|
235
141
|
|
|
236
|
-
|
|
142
|
+
### `GatesAdminService`
|
|
237
143
|
|
|
238
144
|
```typescript
|
|
239
|
-
|
|
240
|
-
user_id: string;
|
|
241
|
-
email: string;
|
|
242
|
-
name: string;
|
|
243
|
-
enabled: boolean;
|
|
244
|
-
profile_attributes: ProfileAttribute[];
|
|
245
|
-
};
|
|
246
|
-
|
|
247
|
-
type ProfileAttribute = {
|
|
248
|
-
attribute_name: string;
|
|
249
|
-
value: string | boolean | number;
|
|
250
|
-
};
|
|
145
|
+
new GatesAdminService({ baseUrl: string })
|
|
251
146
|
```
|
|
252
147
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
```typescript
|
|
256
|
-
type UserListResponse = {
|
|
257
|
-
profiles: Profile[];
|
|
258
|
-
total?: number;
|
|
259
|
-
page?: number;
|
|
260
|
-
limit?: number;
|
|
261
|
-
nextToken?: string;
|
|
262
|
-
};
|
|
263
|
-
```
|
|
148
|
+
- `createUser(idToken: string, params: CreateUserParams): Promise<CreateUserResponse>` — Creates user in Gates
|
|
149
|
+
- `updateUser(idToken: string, params: UpdateUserParams): Promise<void>` — Manages user's system access
|
|
264
150
|
|
|
265
|
-
|
|
151
|
+
### Types
|
|
266
152
|
|
|
267
153
|
```typescript
|
|
268
|
-
type
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
154
|
+
type GatesUser = {
|
|
155
|
+
user_id: string; // from 'sub'
|
|
156
|
+
email?: string; // only in id_tokens
|
|
157
|
+
name?: string; // only in id_tokens
|
|
158
|
+
role?: string; // from 'custom:general_role'
|
|
159
|
+
groups: string[]; // from 'cognito:groups'
|
|
160
|
+
token_use: "access" | "id";
|
|
161
|
+
exp: number;
|
|
162
|
+
iat: number;
|
|
273
163
|
};
|
|
274
|
-
```
|
|
275
|
-
|
|
276
|
-
#### Custom Errors
|
|
277
|
-
|
|
278
|
-
- `AuthenticationError`: Base authentication error class
|
|
279
|
-
- `TokenExpiredError`: Token has expired
|
|
280
|
-
- `InvalidTokenError`: Token is invalid or malformed
|
|
281
|
-
- `MissingAuthorizationError`: Authorization header is missing
|
|
282
|
-
|
|
283
|
-
## Environment Variables
|
|
284
|
-
|
|
285
|
-
You can configure the SDK using environment variables:
|
|
286
|
-
|
|
287
|
-
```bash
|
|
288
|
-
# .env file
|
|
289
|
-
GATES_REGION=sa-east-1
|
|
290
|
-
GATES_USER_POOL_ID=sa-east-1_xxxxxxxxx
|
|
291
|
-
GATES_CLIENT_ID=your-cognito-client-id
|
|
292
|
-
GATES_BACKEND_URL=https://your-backend-api.com
|
|
293
|
-
GATES_SYSTEM_NAME=your-system-name
|
|
294
|
-
```
|
|
295
|
-
|
|
296
|
-
Example usage with environment variables:
|
|
297
164
|
|
|
298
|
-
|
|
299
|
-
import { AuthService, UserService } from "@intelicity/gates-sdk";
|
|
300
|
-
|
|
301
|
-
const authService = new AuthService(
|
|
302
|
-
process.env.GATES_REGION!,
|
|
303
|
-
process.env.GATES_USER_POOL_ID!,
|
|
304
|
-
process.env.GATES_CLIENT_ID!
|
|
305
|
-
);
|
|
165
|
+
type GatesRole = "INTERNAL_ADMIN" | "INTERNAL_USER" | "CLIENT_ADMIN" | "CLIENT_USER";
|
|
306
166
|
|
|
307
|
-
const userService = new UserService(
|
|
308
|
-
process.env.GATES_BACKEND_URL!,
|
|
309
|
-
process.env.GATES_SYSTEM_NAME!
|
|
310
|
-
);
|
|
311
167
|
```
|
|
312
168
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
## Security Best Practices
|
|
316
|
-
|
|
317
|
-
### Token Handling
|
|
318
|
-
|
|
319
|
-
- Never log or expose JWT tokens in production
|
|
320
|
-
- Always use HTTPS in production environments
|
|
321
|
-
- Implement proper token refresh mechanisms
|
|
322
|
-
- Store tokens securely on the client side
|
|
323
|
-
|
|
324
|
-
### Error Handling
|
|
325
|
-
|
|
326
|
-
- Don't expose sensitive error details to end users
|
|
327
|
-
- Log authentication failures for security monitoring
|
|
328
|
-
- Implement rate limiting for authentication endpoints
|
|
329
|
-
|
|
330
|
-
### Configuration
|
|
331
|
-
|
|
332
|
-
- Use environment variables for sensitive configuration
|
|
333
|
-
- Validate all configuration parameters at startup
|
|
334
|
-
- Use strong, unique audience values (client IDs)
|
|
169
|
+
### Error Codes
|
|
335
170
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
throw new Error('Authentication failed');
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
// Bad: Exposing sensitive information
|
|
349
|
-
catch (error) {
|
|
350
|
-
throw new Error(`Auth failed: ${error.message}`); // May expose internal details
|
|
351
|
-
}
|
|
352
|
-
```
|
|
171
|
+
| Code | Class | Description |
|
|
172
|
+
| -------------------------- | --------------------------- | ------------------------------- |
|
|
173
|
+
| `TOKEN_EXPIRED` | `TokenExpiredError` | JWT has expired |
|
|
174
|
+
| `INVALID_TOKEN` | `InvalidTokenError` | Invalid or malformed token |
|
|
175
|
+
| `MISSING_AUTHORIZATION` | `MissingAuthorizationError` | Authorization header missing |
|
|
176
|
+
| `UNAUTHORIZED_GROUP` | `UnauthorizedGroupError` | User not in required group |
|
|
177
|
+
| `API_REQUEST_ERROR` | `ApiRequestError` | Gates API request failed |
|
|
178
|
+
| `MISSING_PARAMETER` | `MissingParameterError` | Required parameter missing |
|
|
179
|
+
| `INVALID_PARAMETER` | `InvalidParameterError` | Parameter has invalid value |
|
|
353
180
|
|
|
354
181
|
## Development
|
|
355
182
|
|
|
356
183
|
```bash
|
|
357
|
-
# Install dependencies
|
|
358
184
|
npm install
|
|
359
|
-
|
|
360
|
-
#
|
|
361
|
-
npm run
|
|
362
|
-
|
|
363
|
-
# Lint
|
|
364
|
-
npm run lint
|
|
365
|
-
|
|
366
|
-
# Type check
|
|
367
|
-
npm run typecheck
|
|
368
|
-
|
|
369
|
-
# Run tests
|
|
370
|
-
npm test
|
|
185
|
+
npm run build # tsc && tsc-alias → dist/
|
|
186
|
+
npm run typecheck # tsc --noEmit
|
|
187
|
+
npm test # vitest run
|
|
188
|
+
npm run test:watch # vitest (watch mode)
|
|
371
189
|
```
|
|
372
190
|
|
|
373
191
|
## License
|
|
@@ -1,2 +1,11 @@
|
|
|
1
|
-
|
|
1
|
+
import { AuthService } from "../services/auth-service.js";
|
|
2
|
+
import { GatesUser } from "../models/user.js";
|
|
3
|
+
export declare function extractToken(authorizationHeader: string | undefined): string;
|
|
4
|
+
export declare function authenticate(token: string, service: AuthService): Promise<GatesUser>;
|
|
5
|
+
export declare function authorize(user: GatesUser, requiredGroups: string | string[]): void;
|
|
6
|
+
export type AuthHandlerConfig = {
|
|
7
|
+
service: AuthService;
|
|
8
|
+
requiredGroups?: string | string[];
|
|
9
|
+
};
|
|
10
|
+
export declare function handleAuth(authorizationHeader: string | undefined, config: AuthHandlerConfig): Promise<GatesUser>;
|
|
2
11
|
//# sourceMappingURL=middleware.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../src/auth/middleware.ts"],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../src/auth/middleware.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAC1D,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAM9C,wBAAgB,YAAY,CAAC,mBAAmB,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAa5E;AAED,wBAAsB,YAAY,CAChC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,SAAS,CAAC,CAEpB;AAED,wBAAgB,SAAS,CACvB,IAAI,EAAE,SAAS,EACf,cAAc,EAAE,MAAM,GAAG,MAAM,EAAE,GAChC,IAAI,CAaN;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B,OAAO,EAAE,WAAW,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;CACpC,CAAC;AAEF,wBAAsB,UAAU,CAC9B,mBAAmB,EAAE,MAAM,GAAG,SAAS,EACvC,MAAM,EAAE,iBAAiB,GACxB,OAAO,CAAC,SAAS,CAAC,CASpB"}
|
package/dist/auth/middleware.js
CHANGED
|
@@ -1,40 +1,31 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
// request.user = user;
|
|
33
|
-
// } catch (err) {
|
|
34
|
-
// if (err instanceof Error && err.message.includes("expired")) {
|
|
35
|
-
// throw new TokenExpiredError();
|
|
36
|
-
// }
|
|
37
|
-
// throw new InvalidTokenError();
|
|
38
|
-
// }
|
|
39
|
-
// };
|
|
40
|
-
// }
|
|
1
|
+
import { MissingAuthorizationError, UnauthorizedGroupError, } from "../errors/error.js";
|
|
2
|
+
export function extractToken(authorizationHeader) {
|
|
3
|
+
if (!authorizationHeader) {
|
|
4
|
+
throw new MissingAuthorizationError();
|
|
5
|
+
}
|
|
6
|
+
const match = /^Bearer\s+(.+)$/i.exec(authorizationHeader);
|
|
7
|
+
if (!match) {
|
|
8
|
+
throw new MissingAuthorizationError("Authorization header must use Bearer scheme");
|
|
9
|
+
}
|
|
10
|
+
return match[1];
|
|
11
|
+
}
|
|
12
|
+
export async function authenticate(token, service) {
|
|
13
|
+
return service.verifyToken(token);
|
|
14
|
+
}
|
|
15
|
+
export function authorize(user, requiredGroups) {
|
|
16
|
+
const groups = Array.isArray(requiredGroups)
|
|
17
|
+
? requiredGroups
|
|
18
|
+
: [requiredGroups];
|
|
19
|
+
const hasGroup = user.groups.some((g) => groups.includes(g));
|
|
20
|
+
if (!hasGroup) {
|
|
21
|
+
throw new UnauthorizedGroupError(`User must be a member of one of the following groups: ${groups.join(", ")}`, groups);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
export async function handleAuth(authorizationHeader, config) {
|
|
25
|
+
const token = extractToken(authorizationHeader);
|
|
26
|
+
const user = await authenticate(token, config.service);
|
|
27
|
+
if (config.requiredGroups) {
|
|
28
|
+
authorize(user, config.requiredGroups);
|
|
29
|
+
}
|
|
30
|
+
return user;
|
|
31
|
+
}
|
package/dist/errors/error.d.ts
CHANGED
|
@@ -1,26 +1,34 @@
|
|
|
1
|
-
|
|
2
|
-
* Base error class for authentication-related errors
|
|
3
|
-
*/
|
|
4
|
-
export declare class AuthenticationError extends Error {
|
|
1
|
+
export declare class GatesError extends Error {
|
|
5
2
|
readonly code?: string | undefined;
|
|
6
3
|
constructor(message: string, code?: string | undefined);
|
|
7
4
|
}
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
5
|
+
export declare class AuthenticationError extends GatesError {
|
|
6
|
+
constructor(message: string, code?: string);
|
|
7
|
+
}
|
|
11
8
|
export declare class TokenExpiredError extends AuthenticationError {
|
|
12
9
|
constructor(message?: string);
|
|
13
10
|
}
|
|
14
|
-
/**
|
|
15
|
-
* Error thrown when a token is invalid
|
|
16
|
-
*/
|
|
17
11
|
export declare class InvalidTokenError extends AuthenticationError {
|
|
18
12
|
constructor(message?: string);
|
|
19
13
|
}
|
|
20
|
-
/**
|
|
21
|
-
* Error thrown when authorization header is missing
|
|
22
|
-
*/
|
|
23
14
|
export declare class MissingAuthorizationError extends AuthenticationError {
|
|
24
15
|
constructor(message?: string);
|
|
25
16
|
}
|
|
17
|
+
export declare class UnauthorizedGroupError extends AuthenticationError {
|
|
18
|
+
readonly requiredGroups: string[];
|
|
19
|
+
constructor(message: string, requiredGroups: string[]);
|
|
20
|
+
}
|
|
21
|
+
export declare class ApiError extends GatesError {
|
|
22
|
+
readonly statusCode?: number | undefined;
|
|
23
|
+
constructor(message: string, statusCode?: number | undefined, code?: string);
|
|
24
|
+
}
|
|
25
|
+
export declare class ApiRequestError extends ApiError {
|
|
26
|
+
constructor(message: string, statusCode?: number);
|
|
27
|
+
}
|
|
28
|
+
export declare class MissingParameterError extends GatesError {
|
|
29
|
+
constructor(parameterName: string);
|
|
30
|
+
}
|
|
31
|
+
export declare class InvalidParameterError extends GatesError {
|
|
32
|
+
constructor(parameterName: string, reason?: string);
|
|
33
|
+
}
|
|
26
34
|
//# sourceMappingURL=error.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"error.d.ts","sourceRoot":"","sources":["../../src/errors/error.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"error.d.ts","sourceRoot":"","sources":["../../src/errors/error.ts"],"names":[],"mappings":"AAAA,qBAAa,UAAW,SAAQ,KAAK;aACU,IAAI,CAAC,EAAE,MAAM;gBAA9C,OAAO,EAAE,MAAM,EAAkB,IAAI,CAAC,EAAE,MAAM,YAAA;CAK3D;AAED,qBAAa,mBAAoB,SAAQ,UAAU;gBACrC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM;CAK3C;AAED,qBAAa,iBAAkB,SAAQ,mBAAmB;gBAC5C,OAAO,SAAsB;CAK1C;AAED,qBAAa,iBAAkB,SAAQ,mBAAmB;gBAC5C,OAAO,SAAkB;CAKtC;AAED,qBAAa,yBAA0B,SAAQ,mBAAmB;gBACpD,OAAO,SAAoC;CAKxD;AAED,qBAAa,sBAAuB,SAAQ,mBAAmB;aAChB,cAAc,EAAE,MAAM,EAAE;gBAAzD,OAAO,EAAE,MAAM,EAAkB,cAAc,EAAE,MAAM,EAAE;CAKtE;AAED,qBAAa,QAAS,SAAQ,UAAU;aAGpB,UAAU,CAAC,EAAE,MAAM;gBADnC,OAAO,EAAE,MAAM,EACC,UAAU,CAAC,EAAE,MAAM,YAAA,EACnC,IAAI,CAAC,EAAE,MAAM;CAMhB;AAED,qBAAa,eAAgB,SAAQ,QAAQ;gBAC/B,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM;CAKjD;AAED,qBAAa,qBAAsB,SAAQ,UAAU;gBACvC,aAAa,EAAE,MAAM;CAKlC;AAED,qBAAa,qBAAsB,SAAQ,UAAU;gBACvC,aAAa,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM;CAQnD"}
|