@nauth-toolkit/core 0.3.1 → 0.3.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.
@@ -4,53 +4,35 @@ import { BaseUser } from '../entities/user.entity';
4
4
  import { NAuthConfig } from '../interfaces/config.interface';
5
5
  import { NAuthLogger } from '../utils/nauth-logger';
6
6
  import { InternalAuthAuditService } from './auth-audit.service';
7
- import { ApiKeyResponseDTO, CreateApiKeyResponseDTO } from '../dto/api-key.dto';
8
- /**
9
- * Parameters for creating an API key.
10
- * The owning `userId` is always supplied by the caller (never from request bodies).
11
- */
12
- export interface CreateApiKeyParams {
13
- /** Internal user ID the key authenticates as */
14
- userId: number;
15
- /** Optional label */
16
- name?: string | null;
17
- /** Expiry in days, `null` for never, or `undefined` to trigger the mandatory-expiry error */
18
- expiresInDays?: number | null;
19
- /** Optional IP allowlist (IPs / IPv4 CIDR ranges) */
20
- allowedIps?: string[];
21
- /** Whether an administrator is creating the key on behalf of the user */
22
- createdByAdmin?: boolean;
23
- }
24
- /** Parameters for updating an API key's mutable fields. */
25
- export interface UpdateApiKeyParams {
26
- userId: number;
27
- keyId: string;
28
- name?: string | null;
29
- allowedIps?: string[];
30
- }
31
- /** Result of a successful API key validation. */
7
+ import { CreateApiKeyDTO, UpdateApiKeyDTO, RevokeApiKeyDTO, DeleteApiKeyDTO, ApiKeyResponseDTO, CreateApiKeyResponseDTO, ListApiKeysResponseDTO, RevokeApiKeyResponseDTO, DeleteApiKeyResponseDTO } from '../dto/api-key.dto';
8
+ import { AdminCreateApiKeyDTO, AdminUpdateApiKeyDTO, AdminManageApiKeyDTO } from '../dto/admin-api-key.dto';
9
+ /** Result of a successful API key validation (internal auth path). */
32
10
  export interface ApiKeyValidationResult {
33
11
  /** External key identifier (UUID v4) */
34
12
  keyId: string;
35
- /** Internal owning user ID */
36
- userId: number;
37
- /** Owning user's external identifier (UUID v4) */
13
+ /** Owning user's external identifier (UUID v4) — callers load the user context from this */
38
14
  sub: string;
39
15
  }
40
16
  /**
41
17
  * API Key Service
42
18
  *
43
- * Manages the lifecycle of API keys (create/list/update/revoke/delete) and validates
44
- * keys presented on requests. Keys authenticate as their owning user.
19
+ * Owns the full API key lifecycle and validation. Keys authenticate **as their owning user**.
20
+ *
21
+ * Identity convention (matches the rest of the toolkit):
22
+ * - **Self-service** methods (`createKey`, `listKeys`, `updateKey`, `revokeKey`, `deleteKey`)
23
+ * act on the *currently authenticated* user, resolved from request context. They take no
24
+ * user identifier.
25
+ * - **Admin** methods (`adminCreateKey`, `adminListKeys`, `adminUpdateKey`, `adminRevokeKey`,
26
+ * `adminDeleteKey`) act on a target user identified by `sub`. Protect them with admin auth.
27
+ *
28
+ * Every public method takes a request DTO and returns a response DTO, and validates the DTO at
29
+ * runtime (via {@link ensureValidatedDto}) so non-NestJS callers are protected from invalid input.
45
30
  *
46
31
  * Security:
47
- * - Only a SHA-256 hash of the full key is stored; the plaintext is returned once at creation.
48
- * - Lookup uses a non-secret, indexed `lookupId`; the secret is compared in constant time.
32
+ * - Only a SHA-256 hash of the key is stored; the plaintext is returned once at creation.
33
+ * - Presented keys are hashed and looked up by that hash (indexed, unique) — the plaintext never
34
+ * leaves the caller and is never compared field-by-field.
49
35
  * - Per-key IP allowlists (optional) restrict which source IPs may use a key.
50
- *
51
- * @remarks
52
- * This service does NOT enforce endpoint authorization. Route protection (which endpoints
53
- * accept API keys) is the responsibility of the framework adapter (guard/middleware).
54
36
  */
55
37
  export declare class ApiKeyService {
56
38
  private readonly apiKeyRepository;
@@ -60,49 +42,66 @@ export declare class ApiKeyService {
60
42
  private readonly auditService?;
61
43
  constructor(apiKeyRepository: Repository<BaseApiKey>, userRepository: Repository<BaseUser>, config: NAuthConfig, logger: NAuthLogger, auditService?: InternalAuthAuditService | undefined);
62
44
  /**
63
- * Create a new API key.
45
+ * Create an API key for the currently authenticated user.
64
46
  *
65
- * @param params - Creation parameters (owning userId is required)
66
- * @returns The plaintext key (shown once) plus sanitized metadata
67
47
  * @throws {NAuthException} API_KEY_CREATION_DISABLED, API_KEY_LIMIT_REACHED,
68
48
  * API_KEY_EXPIRY_REQUIRED, API_KEY_INDEFINITE_NOT_ALLOWED, API_KEY_EXPIRY_TOO_LONG,
69
- * VALIDATION_FAILED (invalid IP allowlist), USER_NOT_FOUND
49
+ * VALIDATION_FAILED, FORBIDDEN (not authenticated)
50
+ */
51
+ createKey(dto: CreateApiKeyDTO): Promise<CreateApiKeyResponseDTO>;
52
+ /**
53
+ * List the current user's API keys (sanitized; never includes secrets).
70
54
  */
71
- createKey(params: CreateApiKeyParams): Promise<CreateApiKeyResponseDTO>;
55
+ listKeys(): Promise<ListApiKeysResponseDTO>;
72
56
  /**
73
- * Update a key's mutable fields (name and IP allowlist).
74
- * The secret and expiry are immutable — rotate/extend by deleting and recreating.
57
+ * Update the current user's key (label and/or IP allowlist). Secret and expiry are immutable.
75
58
  *
76
- * @throws {NAuthException} API_KEY_NOT_FOUND, VALIDATION_FAILED
59
+ * @throws {NAuthException} API_KEY_NOT_FOUND, VALIDATION_FAILED, FORBIDDEN
77
60
  */
78
- updateKey(params: UpdateApiKeyParams): Promise<ApiKeyResponseDTO>;
61
+ updateKey(dto: UpdateApiKeyDTO): Promise<ApiKeyResponseDTO>;
79
62
  /**
80
- * List all keys owned by a user (sanitized; never includes secrets).
63
+ * Revoke (soft-delete) one of the current user's keys.
64
+ *
65
+ * @throws {NAuthException} API_KEY_NOT_FOUND, FORBIDDEN
66
+ */
67
+ revokeKey(dto: RevokeApiKeyDTO): Promise<RevokeApiKeyResponseDTO>;
68
+ /**
69
+ * Permanently delete one of the current user's keys.
70
+ *
71
+ * @throws {NAuthException} API_KEY_NOT_FOUND, FORBIDDEN
72
+ */
73
+ deleteKey(dto: DeleteApiKeyDTO): Promise<DeleteApiKeyResponseDTO>;
74
+ /**
75
+ * Create an API key on behalf of a user. Bypasses `allowUserCreation`, but still enforces
76
+ * `maxKeysPerUser`, expiry, and IP-restriction rules.
77
+ *
78
+ * @throws {NAuthException} USER_NOT_FOUND, or any API_KEY_* creation error
79
+ */
80
+ adminCreateKey(dto: AdminCreateApiKeyDTO): Promise<CreateApiKeyResponseDTO>;
81
+ /**
82
+ * List a user's API keys (admin).
83
+ *
84
+ * @throws {NAuthException} USER_NOT_FOUND
85
+ */
86
+ adminListKeys(dto: AdminManageApiKeyDTO): Promise<ListApiKeysResponseDTO>;
87
+ /**
88
+ * Update a user's key (admin).
89
+ *
90
+ * @throws {NAuthException} USER_NOT_FOUND, API_KEY_NOT_FOUND, VALIDATION_FAILED
81
91
  */
82
- listKeys(userId: number): Promise<ApiKeyResponseDTO[]>;
92
+ adminUpdateKey(dto: AdminUpdateApiKeyDTO): Promise<ApiKeyResponseDTO>;
83
93
  /**
84
- * Revoke (soft-delete) a key. The record is retained for audit history.
94
+ * Revoke (soft-delete) a user's key (admin).
85
95
  *
86
- * @throws {NAuthException} API_KEY_NOT_FOUND
96
+ * @throws {NAuthException} USER_NOT_FOUND, API_KEY_NOT_FOUND, VALIDATION_FAILED
87
97
  */
88
- revokeKey(params: {
89
- userId: number;
90
- keyId: string;
91
- reason?: string;
92
- }): Promise<{
93
- success: boolean;
94
- }>;
98
+ adminRevokeKey(dto: AdminManageApiKeyDTO): Promise<RevokeApiKeyResponseDTO>;
95
99
  /**
96
- * Permanently delete a key.
100
+ * Permanently delete a user's key (admin).
97
101
  *
98
- * @throws {NAuthException} API_KEY_NOT_FOUND
102
+ * @throws {NAuthException} USER_NOT_FOUND, API_KEY_NOT_FOUND, VALIDATION_FAILED
99
103
  */
100
- deleteKey(params: {
101
- userId: number;
102
- keyId: string;
103
- }): Promise<{
104
- success: boolean;
105
- }>;
104
+ adminDeleteKey(dto: AdminManageApiKeyDTO): Promise<DeleteApiKeyResponseDTO>;
106
105
  /**
107
106
  * Validate a presented API key and resolve its owner.
108
107
  *
@@ -111,10 +110,45 @@ export declare class ApiKeyService {
111
110
  *
112
111
  * @param rawKey - The full plaintext key from the request header
113
112
  * @param callerIp - Source IP of the request (for IP-allowlist enforcement + usage tracking)
114
- * @returns The owning user's identifiers on success
115
113
  * @throws {NAuthException} API_KEY_INVALID, API_KEY_EXPIRED, API_KEY_IP_NOT_ALLOWED
116
114
  */
117
115
  validateKey(rawKey: string, callerIp?: string | null): Promise<ApiKeyValidationResult>;
116
+ /**
117
+ * Core key creation for a resolved user.
118
+ */
119
+ private createForUser;
120
+ /**
121
+ * List a resolved user's keys.
122
+ */
123
+ private listForUser;
124
+ /**
125
+ * Update a resolved user's key (label / IP allowlist).
126
+ */
127
+ private updateForUser;
128
+ /**
129
+ * Revoke (soft-delete) a resolved user's key.
130
+ */
131
+ private revokeForUser;
132
+ /**
133
+ * Permanently delete a resolved user's key.
134
+ */
135
+ private deleteForUser;
136
+ /**
137
+ * Resolve the currently authenticated user from request context.
138
+ *
139
+ * @throws {NAuthException} FORBIDDEN when no authenticated user is present
140
+ */
141
+ private getCurrentUserOrThrow;
142
+ /**
143
+ * Resolve an internal user id from an external sub (UUID).
144
+ *
145
+ * @throws {NAuthException} USER_NOT_FOUND
146
+ */
147
+ private resolveUserIdBySub;
148
+ /**
149
+ * Ensure a keyId is present for admin revoke/delete operations.
150
+ */
151
+ private requireKeyId;
118
152
  /**
119
153
  * Resolve the mandatory, config-bounded expiry.
120
154
  */
@@ -124,17 +158,9 @@ export declare class ApiKeyService {
124
158
  */
125
159
  private normalizeAllowedIps;
126
160
  /**
127
- * Compute the SHA-256 hex hash of a full key string.
161
+ * Compute the SHA-256 hex hash of a key string (used for storage + indexed lookup).
128
162
  */
129
163
  private hashKey;
130
- /**
131
- * Constant-time comparison of two equal-length hex hashes.
132
- */
133
- private hashesEqual;
134
- /**
135
- * Extract the non-secret lookup id from a raw key of the form `prefix_lookupId.secret`.
136
- */
137
- private parseLookupId;
138
164
  /**
139
165
  * Update last-used metadata, throttled to avoid a write on every request.
140
166
  * Never throws — usage tracking must not block authentication.
@@ -1 +1 @@
1
- {"version":3,"file":"api-key.service.d.ts","sourceRoot":"","sources":["../../src/services/api-key.service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"api-key.service.d.ts","sourceRoot":"","sources":["../../src/services/api-key.service.ts"],"names":[],"mappings":"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"}