@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.
- package/dist/dto/api-key.dto.d.ts +21 -0
- package/dist/dto/api-key.dto.d.ts.map +1 -1
- package/dist/dto/api-key.dto.js +25 -1
- package/dist/dto/api-key.dto.js.map +1 -1
- package/dist/entities/api-key.entity.d.ts +4 -10
- package/dist/entities/api-key.entity.d.ts.map +1 -1
- package/dist/entities/api-key.entity.js +4 -10
- package/dist/entities/api-key.entity.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/interfaces/config.interface.d.ts +0 -6
- package/dist/interfaces/config.interface.d.ts.map +1 -1
- package/dist/openapi/components.schemas.json +45 -0
- package/dist/schemas/auth-config.schema.d.ts +64 -74
- package/dist/schemas/auth-config.schema.d.ts.map +1 -1
- package/dist/schemas/auth-config.schema.js +0 -1
- package/dist/schemas/auth-config.schema.js.map +1 -1
- package/dist/services/admin-auth.service.d.ts +1 -59
- package/dist/services/admin-auth.service.d.ts.map +1 -1
- package/dist/services/admin-auth.service.js +1 -99
- package/dist/services/admin-auth.service.js.map +1 -1
- package/dist/services/api-key.service.d.ts +100 -74
- package/dist/services/api-key.service.d.ts.map +1 -1
- package/dist/services/api-key.service.js +247 -150
- package/dist/services/api-key.service.js.map +1 -1
- package/dist/utils/setup/init-services.d.ts.map +1 -1
- package/dist/utils/setup/init-services.js +1 -1
- package/dist/utils/setup/init-services.js.map +1 -1
- package/package.json +2 -2
|
@@ -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
|
-
|
|
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
|
-
/**
|
|
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
|
-
*
|
|
44
|
-
*
|
|
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
|
|
48
|
-
* -
|
|
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
|
|
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 (
|
|
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
|
-
|
|
55
|
+
listKeys(): Promise<ListApiKeysResponseDTO>;
|
|
72
56
|
/**
|
|
73
|
-
* Update
|
|
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(
|
|
61
|
+
updateKey(dto: UpdateApiKeyDTO): Promise<ApiKeyResponseDTO>;
|
|
79
62
|
/**
|
|
80
|
-
*
|
|
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
|
-
|
|
92
|
+
adminUpdateKey(dto: AdminUpdateApiKeyDTO): Promise<ApiKeyResponseDTO>;
|
|
83
93
|
/**
|
|
84
|
-
* Revoke (soft-delete) a key
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAErC,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AACxD,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"api-key.service.d.ts","sourceRoot":"","sources":["../../src/services/api-key.service.ts"],"names":[],"mappings":"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"}
|