@xenterprises/fastify-xauth-jwks 1.1.1 → 1.1.2

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@xenterprises/fastify-xauth-jwks",
3
3
  "type": "module",
4
- "version": "1.1.1",
4
+ "version": "1.1.2",
5
5
  "description": "Fastify plugin for path-based JWT/JWKS validation. Protect multiple paths with independent JWKS providers.",
6
6
  "main": "src/index.js",
7
7
  "exports": {
package/server/app.js DELETED
@@ -1,370 +0,0 @@
1
- /**
2
- * xAuthJWSK Demo Server
3
- *
4
- * Shows path-based JWT/JWKS validation with flexible configuration:
5
- * - Development: Local JWKS data (example-jwks.json)
6
- * - Production: Remote JWKS URLs (via environment variables)
7
- *
8
- * Environment Variables:
9
- * USE_LOCAL_JWKS=true - Force local JWKS (dev mode)
10
- * ADMIN_JWKS_URL=https://... - Admin path JWKS endpoint
11
- * PORTAL_JWKS_URL=https://... - Portal path JWKS endpoint
12
- * PARTNER_JWKS_URL=https://... - Partner path JWKS endpoint
13
- * PORT=3000 - Server port (default: 3000)
14
- *
15
- * Quick Start (Development):
16
- * npm run dev
17
- * node server/generate-demo-token.js admin user-123 admin
18
- * curl -H "Authorization: Bearer <TOKEN>" http://localhost:3000/admin/dashboard
19
- *
20
- * Production Setup:
21
- * export ADMIN_JWKS_URL="https://auth.example.com/.well-known/jwks.json"
22
- * export PORTAL_JWKS_URL="https://auth.example.com/.well-known/jwks.json"
23
- * npm start
24
- */
25
-
26
- import Fastify from "fastify";
27
- import xAuthJWSK from "../src/xAuth.js";
28
- import { extractToken, decodeToken, decodeHeader, requireRole } from "../src/utils/index.js";
29
- import exampleJwks from "./example-jwks.json" assert { type: "json" };
30
-
31
- const fastify = Fastify({
32
- logger: true,
33
- });
34
-
35
- // ============================================================================
36
- // Configuration Strategy
37
- // ============================================================================
38
- // Flexible configuration for both development and production:
39
- // - Development: Use local JWKS (example-jwks.json) - no external calls
40
- // - Production: Use remote JWKS URLs from environment variables
41
- const useLocalJwks = process.env.USE_LOCAL_JWKS === "true" || !process.env.ADMIN_JWKS_URL;
42
-
43
- // ============================================================================
44
- // Register xAuthJWSK Plugin
45
- // ============================================================================
46
- // Protect multiple API paths with independent JWKS providers
47
- // Each path can have different JWKS source, caching strategy, excluded paths
48
- // See CONFIGURATION.md for complete reference
49
- await fastify.register(xAuthJWSK, {
50
- paths: {
51
- // ========================================================================
52
- // ADMIN API - Strict authentication (e.g., internal admin panel)
53
- // ========================================================================
54
- // Protected: /admin/*
55
- // Excluded: /admin/health, /admin/status
56
- // Use case: Internal dashboards, user management, sensitive operations
57
- admin: {
58
- pathPattern: "/admin",
59
- // JWKS: Local OR remote (not both) - choose one
60
- ...(useLocalJwks
61
- ? { jwksData: exampleJwks } // Development: local file
62
- : { jwksUrl: process.env.ADMIN_JWKS_URL || "https://example.com/admin/.well-known/jwks.json" }), // Production: env var
63
- // Paths that don't require authentication (health checks, etc)
64
- excludedPaths: ["/health", "/status"],
65
- // Caching: Strict cache - refresh every 5 minutes
66
- enablePayloadCache: true,
67
- payloadCacheTTL: 300000, // 5 min token payload cache
68
- jwksCacheMaxAge: 1800000, // 30 min JWKS cache (production keys rarely change)
69
- },
70
-
71
- // ========================================================================
72
- // PORTAL API - User-facing (e.g., SaaS application)
73
- // ========================================================================
74
- // Protected: /portal/*
75
- // Excluded: /portal/public/*, /portal/docs
76
- // Use case: User dashboards, API access, profile management
77
- portal: {
78
- pathPattern: "/portal",
79
- ...(useLocalJwks
80
- ? { jwksData: exampleJwks }
81
- : { jwksUrl: process.env.PORTAL_JWKS_URL || "https://example.com/portal/.well-known/jwks.json" }),
82
- // Public endpoints (marketing pages, documentation)
83
- excludedPaths: ["/public", "/docs"],
84
- // Caching: Standard cache - balance performance and freshness
85
- enablePayloadCache: true,
86
- payloadCacheTTL: 300000, // 5 min
87
- },
88
-
89
- // ========================================================================
90
- // PARTNER API - Integration endpoint (e.g., webhooks, B2B integrations)
91
- // ========================================================================
92
- // Protected: /partner/*
93
- // No excluded paths - all routes require authentication
94
- // Use case: Partner integrations, webhooks, third-party API access
95
- partner: {
96
- pathPattern: "/partner",
97
- ...(useLocalJwks
98
- ? { jwksData: exampleJwks }
99
- : { jwksUrl: process.env.PARTNER_JWKS_URL || "https://example.com/partner/.well-known/jwks.json" }),
100
- // All routes require authentication - no exclusions
101
- // Longer cache TTL - partner tokens typically valid longer
102
- enablePayloadCache: true,
103
- payloadCacheTTL: 600000, // 10 min - partners have longer-lived tokens
104
- },
105
- },
106
- });
107
-
108
- // ============================================================================
109
- // Public Routes (No Authentication Required)
110
- // ============================================================================
111
-
112
- fastify.get("/", async () => {
113
- return {
114
- service: "xAuthJWSK Demo",
115
- version: "1.0.0",
116
- protectedPaths: Object.keys(fastify.xAuth.validators),
117
- docs: "https://github.com/xenterprises/fastify-xauth-jwks",
118
- };
119
- });
120
-
121
- fastify.get("/health", async () => {
122
- return { status: "ok", timestamp: new Date().toISOString() };
123
- });
124
-
125
- // ============================================================================
126
- // Admin Routes (Protected by /admin)
127
- // ============================================================================
128
-
129
- fastify.get("/admin/health", async () => {
130
- return { status: "healthy", service: "admin-api" };
131
- });
132
-
133
- fastify.get("/admin/status", async () => {
134
- return { status: "operational", uptime: process.uptime() };
135
- });
136
-
137
- fastify.get("/admin/dashboard", async (request) => {
138
- return {
139
- message: "Admin Dashboard",
140
- userId: request.auth.userId,
141
- user: request.auth.payload,
142
- authenticatedVia: request.auth.path,
143
- };
144
- });
145
-
146
- fastify.get("/admin/users", async (request) => {
147
- return {
148
- message: "List of users",
149
- adminId: request.auth.userId,
150
- users: [
151
- { id: "user_1", name: "John Doe", email: "john@example.com" },
152
- { id: "user_2", name: "Jane Smith", email: "jane@example.com" },
153
- ],
154
- };
155
- });
156
-
157
- fastify.get("/admin/settings", {
158
- preHandler: requireRole("admin"),
159
- handler: async (request) => {
160
- return {
161
- message: "Admin settings (admin role required)",
162
- adminId: request.auth.userId,
163
- roles: request.user?.roles || [],
164
- };
165
- },
166
- });
167
-
168
- // Cache management endpoint
169
- fastify.post("/admin/cache/clear", async (request) => {
170
- const validator = fastify.xAuth.validators.admin;
171
- validator.clearPayloadCache();
172
- return {
173
- message: "Cache cleared",
174
- stats: validator.getPayloadCacheStats(),
175
- };
176
- });
177
-
178
- fastify.get("/admin/cache/stats", async (request) => {
179
- const stats = {};
180
- for (const [name, validator] of Object.entries(fastify.xAuth.validators)) {
181
- stats[name] = validator.getPayloadCacheStats();
182
- }
183
- return { cacheStats: stats };
184
- });
185
-
186
- // ============================================================================
187
- // Portal Routes (Protected by /portal)
188
- // ============================================================================
189
-
190
- fastify.get("/portal/dashboard", async (request) => {
191
- return {
192
- message: "Portal Dashboard",
193
- userId: request.auth.userId,
194
- user: request.auth.payload,
195
- };
196
- });
197
-
198
- fastify.get("/portal/profile", async (request) => {
199
- return {
200
- message: "User Profile",
201
- userId: request.auth.userId,
202
- email: request.user?.email,
203
- name: request.user?.name,
204
- };
205
- });
206
-
207
- fastify.get("/portal/public/docs", async () => {
208
- return {
209
- message: "API Documentation",
210
- endpoints: ["GET /portal/dashboard", "GET /portal/profile", "POST /portal/update"],
211
- };
212
- });
213
-
214
- fastify.get("/portal/public/pricing", async () => {
215
- return {
216
- plans: [
217
- { tier: "free", price: 0 },
218
- { tier: "pro", price: 29 },
219
- { tier: "enterprise", price: 299 },
220
- ],
221
- };
222
- });
223
-
224
- // ============================================================================
225
- // Partner Routes (Protected by /partner)
226
- // ============================================================================
227
-
228
- fastify.get("/partner/api/data", async (request) => {
229
- return {
230
- message: "Partner API Data",
231
- partnerId: request.auth.userId,
232
- data: { status: "connected", lastSync: new Date().toISOString() },
233
- };
234
- });
235
-
236
- fastify.get("/partner/api/webhooks", async (request) => {
237
- return {
238
- message: "Partner Webhooks",
239
- partnerId: request.auth.userId,
240
- webhooks: [
241
- { id: "wh_1", event: "user.created", url: "https://partner.example.com/webhooks" },
242
- ],
243
- };
244
- });
245
-
246
- // ============================================================================
247
- // Token Inspection Endpoints (No Auth Required - for debugging)
248
- // ============================================================================
249
-
250
- fastify.post("/debug/decode-token", async (request, reply) => {
251
- const { token } = request.body;
252
-
253
- if (!token) {
254
- return reply.code(400).send({ error: "Token required" });
255
- }
256
-
257
- try {
258
- const header = decodeHeader(token);
259
- const payload = decodeToken(token);
260
-
261
- return {
262
- header,
263
- payload,
264
- warning: "āš ļø This is UNVERIFIED token data. Only for debugging. Do NOT trust in production.",
265
- };
266
- } catch (error) {
267
- return reply.code(400).send({ error: "Invalid token format" });
268
- }
269
- });
270
-
271
- fastify.post("/debug/extract-token", async (request, reply) => {
272
- const authHeader = request.headers.authorization;
273
-
274
- if (!authHeader) {
275
- return reply.code(400).send({ error: "Authorization header required" });
276
- }
277
-
278
- const token = extractToken(request);
279
-
280
- if (!token) {
281
- return reply.code(400).send({ error: "Invalid Bearer token format" });
282
- }
283
-
284
- try {
285
- const payload = decodeToken(token);
286
- return {
287
- extracted: true,
288
- userId: payload.sub,
289
- expiresAt: new Date(payload.exp * 1000).toISOString(),
290
- payload,
291
- };
292
- } catch (error) {
293
- return reply.code(400).send({ error: "Failed to decode token" });
294
- }
295
- });
296
-
297
- // ============================================================================
298
- // Validator Inspection Endpoint
299
- // ============================================================================
300
-
301
- fastify.get("/admin/validators", async (request) => {
302
- const validators = {};
303
- for (const [name, validator] of Object.entries(fastify.xAuth.validators)) {
304
- validators[name] = {
305
- name: validator.name,
306
- pathPattern: validator.pathPattern,
307
- jwksUrl: validator.jwksUrl,
308
- config: validator.config,
309
- cacheStats: validator.getPayloadCacheStats(),
310
- };
311
- }
312
- return { validators };
313
- });
314
-
315
- // ============================================================================
316
- // Server Startup
317
- // ============================================================================
318
-
319
- const start = async () => {
320
- try {
321
- await fastify.listen({ port: process.env.PORT || 3000, host: "0.0.0.0" });
322
-
323
- console.log("\nšŸš€ xAuthJWSK Demo Server Started!\n");
324
- console.log(`Mode: ${useLocalJwks ? "šŸ  LOCAL (Development)" : "ā˜ļø REMOTE (Production)"}`);
325
- if (useLocalJwks) {
326
- console.log(" Using example-jwks.json - perfect for testing!");
327
- console.log(" Generate test tokens: node server/generate-demo-token.js [path] [userId] [role]");
328
- }
329
- console.log("\nProtected Paths:");
330
- for (const [name, validator] of Object.entries(fastify.xAuth.validators)) {
331
- console.log(`\n šŸ“ ${name.toUpperCase()}`);
332
- console.log(` Path: ${validator.pathPattern}`);
333
- console.log(` JWKS: ${useLocalJwks ? "local (example-jwks.json)" : validator.jwksUrl}`);
334
- console.log(` Cache: ${validator.config.enablePayloadCache ? "enabled" : "disabled"}`);
335
- }
336
-
337
- console.log("\n\nPublic Endpoints:");
338
- console.log(" GET / - API info");
339
- console.log(" GET /health - Health check");
340
- console.log(" POST /debug/decode-token - Decode JWT (debug only)");
341
- console.log(" POST /debug/extract-token - Extract token from header");
342
- console.log(" GET /admin/validators - View validator configs");
343
-
344
- console.log("\n\nProtected Endpoints (require Bearer token):");
345
- console.log(" GET /admin/dashboard - Admin dashboard");
346
- console.log(" GET /admin/users - List users");
347
- console.log(" GET /admin/settings - Settings (requires 'admin' role)");
348
- console.log(" POST /admin/cache/clear - Clear auth cache");
349
- console.log(" GET /admin/cache/stats - View cache statistics");
350
- console.log(" GET /portal/dashboard - Portal dashboard");
351
- console.log(" GET /portal/profile - User profile");
352
- console.log(" GET /partner/api/data - Partner data");
353
-
354
- if (useLocalJwks) {
355
- console.log("\n\n🧪 Testing with Local JWKS:");
356
- console.log(" 1. Generate a test token:");
357
- console.log(" node server/generate-demo-token.js admin user-123 admin");
358
- console.log(" 2. Copy the token and test a protected endpoint:");
359
- console.log(" curl -H \"Authorization: Bearer <TOKEN>\" http://localhost:3000/admin/dashboard");
360
- console.log(" 3. For more info, see KEYS_GENERATION.md and QUICK_START.md");
361
- }
362
-
363
- console.log("\nšŸ’” Tip: Add '-H \"Authorization: Bearer YOUR_TOKEN\"' to protected requests\n");
364
- } catch (err) {
365
- fastify.log.error(err);
366
- process.exit(1);
367
- }
368
- };
369
-
370
- start();
@@ -1,12 +0,0 @@
1
- {
2
- "keys": [
3
- {
4
- "kty": "RSA",
5
- "use": "sig",
6
- "alg": "RS256",
7
- "kid": "demo-key-admin",
8
- "n": "xjlCRBqkQWeBpaMWV2E2h6L1zcqmxm0W3Z5BbMwP9jfYEJ_ZHvMdV8fYaWDV8xzGqL7Z9fQaL7bXmVzYcPz0Xq5L_VmE8V7K0L1M2N3O4P5Q6R7S8T9U0V1W2X3Y4Z5A6B7C8D9E0F1G2H3I4J5K6L7M8N9O0P1Q2R3S4T5U6V7W8X9Y0Z1A2B3C4D5E6F7G8H9I0J1K2L3M4N5O6P7Q8R9S0T1U2V3W4X5Y6Z7A8B9C0D1E2F3G4H5I6J7K8L9M0N1O2P3Q4R5S6T7U8V9W0X1Y2Z3A4B5C6D7E8F9G0H1I2J3K4L5M6N7O8P9Q0R1S2T3U4V5W6X7Y8Z9",
9
- "e": "AQAB"
10
- }
11
- ]
12
- }
@@ -1,232 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * Generate demo JWT tokens for testing xAuthJWSK
5
- *
6
- * Usage:
7
- * node generate-demo-token.js [pathName] [userId] [role]
8
- *
9
- * Examples:
10
- * node generate-demo-token.js admin user-123 admin
11
- * node generate-demo-token.js portal user-456 user
12
- * node generate-demo-token.js partner partner-789
13
- */
14
-
15
- import * as jose from 'jose';
16
-
17
- // Demo JWKS keys - these are public keys only
18
- // In production, private keys would be stored securely
19
- const demoKeys = {
20
- admin: {
21
- kid: 'demo-key-admin',
22
- // This is a demo key for testing ONLY - never use in production
23
- privateKeyPem: `-----BEGIN PRIVATE KEY-----
24
- MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDGOUJEGqRBZ4Gl
25
- oxZXYTaHovXNyqbGbRbdnkFszA/2N9gQn9ke8x1Xx9hpYNXzHMaovtn19BovttmZ
26
- XNhw/PRerkv9WYTxXsrQnUjczUjczVTNzNT0xM01M1MzQzM1M9T1M9M1TzU0MzU0
27
- M1MzQzMzQ0M1MzMzM1M1QzMzMzM1RDMzM1M1QzMzM1M1QzMzM1M1M1MzMzM1M1Mz
28
- MzM1M1MzMzM1M1MzMzMzUzMzMzM1M1MzMzMzUzMzMzM1M1MzMzMzUzMzMzM1M1Mz
29
- MzMzUzMzMzM1M1MzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMz
30
- MzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMz
31
- MzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMz
32
- AgMBAAECggEAQQECDQwVFBcWGRgbHBwdHR4eHx8gICEhISIiIiIjIyMjIyMkJCQk
33
- JCQlJSUlJSUlJSYmJiYmJiYmJiYnJycnJycnJycnJycnJycnJycnJycnJycnJycnJ
34
- yckJycnJycnJycoJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJyc
35
- nJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
36
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
37
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
38
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
39
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
40
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
41
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
42
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
43
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
44
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
45
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
46
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
47
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
48
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
49
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
50
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
51
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
52
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
53
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
54
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
55
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
56
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
57
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
58
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
59
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
60
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
61
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
62
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
63
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
64
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
65
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
66
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
67
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
68
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
69
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
70
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
71
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
72
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
73
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
74
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
75
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
76
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
77
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
78
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
79
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
80
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
81
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
82
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
83
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
84
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
85
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
86
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
87
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
88
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
89
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
90
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
91
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
92
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
93
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
94
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
95
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
96
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
97
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
98
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
99
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
100
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
101
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
102
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
103
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
104
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
105
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
106
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
107
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
108
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
109
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
110
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
111
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
112
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
113
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
114
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
115
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
116
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
117
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
118
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
119
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
120
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
121
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
122
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
123
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
124
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
125
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
126
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
127
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
128
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
129
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
130
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
131
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
132
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
133
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
134
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
135
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
136
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
137
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
138
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
139
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
140
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
141
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
142
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
143
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
144
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
145
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
146
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
147
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
148
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
149
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
150
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
151
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
152
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
153
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
154
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
155
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
156
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
157
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
158
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
159
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
160
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
161
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
162
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
163
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
164
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
165
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
166
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
167
- cnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJy
168
- -----END PRIVATE KEY-----`,
169
- },
170
- };
171
-
172
- async function generateToken() {
173
- const args = process.argv.slice(2);
174
- const pathName = args[0] || 'admin';
175
- const userId = args[1] || 'user-' + Math.random().toString(36).substring(7);
176
- const role = args[2] || 'user';
177
-
178
- const keyConfig = demoKeys[pathName];
179
- if (!keyConfig) {
180
- console.error(`āŒ No demo key for path: ${pathName}`);
181
- console.error(` Available paths: ${Object.keys(demoKeys).join(', ')}`);
182
- process.exit(1);
183
- }
184
-
185
- try {
186
- // Import private key
187
- const privateKey = await jose.importPKCS8(
188
- keyConfig.privateKeyPem,
189
- 'RS256'
190
- );
191
-
192
- // Create JWT
193
- const token = await new jose.SignJWT({
194
- sub: userId,
195
- userId: userId,
196
- name: `Test User (${pathName})`,
197
- email: `${userId}@example.com`,
198
- roles: [role],
199
- iat: Math.floor(Date.now() / 1000),
200
- exp: Math.floor(Date.now() / 1000) + 3600, // 1 hour
201
- })
202
- .setProtectedHeader({
203
- alg: 'RS256',
204
- kid: `demo-key-${pathName}`,
205
- typ: 'JWT',
206
- })
207
- .sign(privateKey);
208
-
209
- console.log('šŸŽ« Generated Test Token:\n');
210
- console.log(token);
211
- console.log('\nšŸ“‹ Token Details:');
212
- console.log(` Path: ${pathName}`);
213
- console.log(` User ID: ${userId}`);
214
- console.log(` Role: ${role}`);
215
- console.log(` Expires: 1 hour`);
216
- console.log('\nšŸ”— Usage Examples:\n');
217
- console.log('# cURL:');
218
- console.log(`curl -H "Authorization: Bearer ${token}" \\`);
219
- console.log(` http://localhost:3000/${pathName}/dashboard\n`);
220
- console.log('# JavaScript fetch:');
221
- console.log(`fetch('http://localhost:3000/${pathName}/dashboard', {`);
222
- console.log(` headers: { Authorization: 'Bearer ${token}' }`);
223
- console.log(`})\n`);
224
- console.log('# Decode token (for inspection):');
225
- console.log(`node -e "console.log(JSON.stringify(JSON.parse(Buffer.from('${token}'.split('.')[1], 'base64').toString()), null, 2))"\n`);
226
- } catch (error) {
227
- console.error('āŒ Error generating token:', error.message);
228
- process.exit(1);
229
- }
230
- }
231
-
232
- generateToken();