Skip to content

Commit c895f39

Browse files
committed
feat: add JWT secret validation and bump version to 0.3.3
1 parent 4a4db34 commit c895f39

8 files changed

Lines changed: 52 additions & 20 deletions

File tree

.github/workflows/publish.yml

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,30 @@ on:
77
jobs:
88
build:
99
runs-on: ubuntu-latest
10+
permissions:
11+
contents: read
12+
packages: write
13+
id-token: write
14+
1015
steps:
1116
- uses: actions/checkout@v4
17+
1218
- uses: actions/setup-node@v4
1319
with:
1420
node-version: '18.x'
1521
registry-url: 'https://registry.npmjs.org'
16-
- run: npm ci
17-
- run: npm test
18-
- run: npm run build
19-
- run: npm publish --access public
22+
scope: '@humanjavaenterprises'
23+
24+
- name: Install dependencies
25+
run: npm ci
26+
27+
- name: Run tests
28+
run: npm test
29+
30+
- name: Build package
31+
run: npm run build
32+
33+
- name: Publish to NPM
34+
run: npm publish --access public
2035
env:
2136
NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,11 +92,15 @@ This middleware follows key principles that promote security, auditability, and
9292
### Basic Setup
9393
```javascript
9494
const auth = new NostrAuthMiddleware({
95-
jwtSecret: process.env.JWT_SECRET, // Required
95+
jwtSecret: process.env.JWT_SECRET, // Required in production
9696
expiresIn: '24h' // Optional, defaults to '24h'
9797
});
9898
```
9999

100+
### Environment-Specific Behavior
101+
- **Production**: JWT_SECRET is required. The middleware will throw an error if not provided
102+
- **Development**: A default development-only secret is used if JWT_SECRET is not provided (not secure for production use)
103+
100104
### JWT Operations
101105

102106
#### Token Generation

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "nostr-auth-middleware",
3-
"version": "0.3.2",
3+
"version": "0.3.3",
44
"description": "A focused, security-first authentication middleware for Nostr applications",
55
"author": "vveerrgg",
66
"type": "module",

src/__tests__/nostr-auth.middleware.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { describe, it, expect, vi, beforeEach } from 'vitest';
22
import { Request, Response, NextFunction } from 'express';
33
import { NostrAuthMiddleware } from '../middleware/nostr-auth.middleware.js';
44
import { NostrService } from '../services/nostr.service.js';
5-
import { NostrEvent, NostrChallenge, VerificationResult, NostrAuthConfig, JWTExpiresIn } from '../types/index.js';
5+
import type { NostrEvent, NostrChallenge, VerificationResult, NostrAuthConfig, JWTExpiresIn } from '../types.js';
66

77
// Mock NostrService
88
vi.mock('../services/nostr.service.js');
@@ -14,14 +14,14 @@ describe('NostrAuthMiddleware', () => {
1414
let mockNext: NextFunction;
1515
let mockNostrService: NostrService;
1616

17-
const testConfig: NostrAuthConfig = {
17+
const testConfig: Partial<NostrAuthConfig> = {
1818
jwtSecret: 'test-secret-key',
19-
jwtExpiresIn: '24h' satisfies JWTExpiresIn,
19+
jwtExpiresIn: '24h' as JWTExpiresIn,
2020
eventTimeoutMs: 5000,
2121
keyManagementMode: 'development' as const,
2222
port: 3000,
2323
nodeEnv: 'test',
24-
corsOrigins: '*',
24+
corsOrigin: '*',
2525
supabaseUrl: 'http://localhost:54321',
2626
supabaseKey: 'test-key',
2727
testMode: true

src/config/index.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,9 @@ export const config: NostrConfig = {
5454
privateKey: process.env.SERVER_PRIVATE_KEY,
5555
keyManagementMode: (process.env.KEY_MANAGEMENT_MODE as 'development' | 'production') || 'development',
5656
// Auth config
57-
jwtSecret: process.env.JWT_SECRET || 'maiqr_nostr_auth_secret_key_2024',
57+
jwtSecret: process.env.JWT_SECRET || (process.env.NODE_ENV === 'production'
58+
? (() => { throw new Error('JWT_SECRET is required in production mode') })()
59+
: 'development_jwt_secret_do_not_use_in_production'),
5860
jwtExpiresIn: '1h',
5961
testMode: process.env.TEST_MODE === 'true',
6062
// Optional configs
@@ -111,7 +113,9 @@ export async function loadConfig(envPath?: string): Promise<NostrConfig> {
111113
publicKey: process.env.SERVER_PUBLIC_KEY,
112114
keyManagementMode: process.env.KEY_MANAGEMENT_MODE as 'development' | 'production',
113115
// Auth config
114-
jwtSecret: process.env.JWT_SECRET,
116+
jwtSecret: process.env.JWT_SECRET || (process.env.NODE_ENV === 'production'
117+
? (() => { throw new Error('JWT_SECRET is required in production mode') })()
118+
: 'development_jwt_secret_do_not_use_in_production'),
115119
jwtExpiresIn: process.env.JWT_EXPIRES_IN || '24h',
116120
testMode: process.env.NODE_ENV !== 'production',
117121
// Optional configs

src/middleware/nostr-auth.middleware.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,16 @@
55

66
import { Request, Response, NextFunction, Router } from 'express';
77
import { NostrService } from '../services/nostr.service.js';
8-
import { NostrEvent, NostrAuthConfig } from '../types.js';
8+
import type { NostrEvent, NostrAuthConfig, JWTExpiresIn } from '../types.js';
99
import { createLogger } from '../utils/logger.js';
1010

1111
const logger = createLogger('NostrAuthMiddleware');
1212

13-
const DEFAULT_CONFIG: Required<Pick<NostrAuthConfig, 'keyManagementMode' | 'eventTimeoutMs' | 'jwtExpiresIn'>> = {
13+
const DEFAULT_CONFIG: Required<Pick<NostrAuthConfig, 'keyManagementMode' | 'eventTimeoutMs' | 'jwtExpiresIn' | 'port'>> = {
1414
keyManagementMode: 'development',
1515
eventTimeoutMs: 300000, // 5 minutes
16-
jwtExpiresIn: '1h'
16+
jwtExpiresIn: '1h' as JWTExpiresIn,
17+
port: 3000 // Default port
1718
};
1819

1920
/**
@@ -37,14 +38,15 @@ export class NostrAuthMiddleware {
3738
}
3839

3940
// Ensure required properties are present with defaults
40-
const fullConfig = {
41+
const fullConfig: NostrAuthConfig = {
4142
...DEFAULT_CONFIG,
4243
...config,
4344
jwtSecret: config.jwtSecret,
45+
port: config.port || DEFAULT_CONFIG.port,
4446
eventTimeoutMs: config.eventTimeoutMs || DEFAULT_CONFIG.eventTimeoutMs,
4547
jwtExpiresIn: config.jwtExpiresIn || DEFAULT_CONFIG.jwtExpiresIn,
4648
keyManagementMode: config.keyManagementMode || DEFAULT_CONFIG.keyManagementMode
47-
} as NostrAuthConfig;
49+
};
4850

4951
this.nostrService = nostrService || new NostrService(fullConfig);
5052
this.router = Router();

src/types.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,11 @@ export interface NostrAuthConfig {
6666
*/
6767
export interface NostrChallenge {
6868
id: string;
69+
pubkey: string;
6970
challenge: string;
71+
event?: NostrEvent;
7072
created_at: number;
7173
expires_at: number;
72-
pubkey: string;
7374
}
7475

7576
/**

src/types/index.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@ import { NostrEvent } from '../interfaces/nostr.interface.js';
88

99
export { NostrEvent };
1010

11+
/**
12+
* Type representing JWT expiration time
13+
* @type {string}
14+
*/
15+
export type JWTExpiresIn = string;
16+
1117
/**
1218
* Interface representing a Nostr authentication challenge
1319
* @interface NostrChallenge
@@ -130,9 +136,9 @@ export interface NostrAuthConfig extends SecurityConfig {
130136
supabaseKey?: string;
131137

132138
/** Secret for JWT signing */
133-
jwtSecret?: string;
139+
jwtSecret: string;
134140
/** JWT expiration time */
135-
jwtExpiresIn?: string;
141+
jwtExpiresIn: JWTExpiresIn;
136142
/** Enable test mode */
137143
testMode?: boolean;
138144
}

0 commit comments

Comments
 (0)