@intelicity/gates-sdk 0.1.6 → 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 +99 -480
- 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 +0 -36
- package/dist/errors/error.d.ts.map +1 -1
- package/dist/errors/error.js +6 -47
- package/dist/index.d.ts +5 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -12
- 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 +32 -46
- 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/package.json +5 -2
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,69 +1,33 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Base error class for all Gates SDK errors
|
|
3
|
-
*/
|
|
4
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
|
-
* Base error class for authentication-related errors
|
|
10
|
-
*/
|
|
11
5
|
export declare class AuthenticationError extends GatesError {
|
|
12
6
|
constructor(message: string, code?: string);
|
|
13
7
|
}
|
|
14
|
-
/**
|
|
15
|
-
* Error thrown when a token has expired
|
|
16
|
-
*/
|
|
17
8
|
export declare class TokenExpiredError extends AuthenticationError {
|
|
18
9
|
constructor(message?: string);
|
|
19
10
|
}
|
|
20
|
-
/**
|
|
21
|
-
* Error thrown when a token is invalid
|
|
22
|
-
*/
|
|
23
11
|
export declare class InvalidTokenError extends AuthenticationError {
|
|
24
12
|
constructor(message?: string);
|
|
25
13
|
}
|
|
26
|
-
/**
|
|
27
|
-
* Error thrown when authorization header is missing
|
|
28
|
-
*/
|
|
29
14
|
export declare class MissingAuthorizationError extends AuthenticationError {
|
|
30
15
|
constructor(message?: string);
|
|
31
16
|
}
|
|
32
|
-
/**
|
|
33
|
-
* Error thrown when user is not a member of required group
|
|
34
|
-
*/
|
|
35
17
|
export declare class UnauthorizedGroupError extends AuthenticationError {
|
|
36
18
|
readonly requiredGroups: string[];
|
|
37
19
|
constructor(message: string, requiredGroups: string[]);
|
|
38
20
|
}
|
|
39
|
-
/**
|
|
40
|
-
* Base error class for API-related errors
|
|
41
|
-
*/
|
|
42
21
|
export declare class ApiError extends GatesError {
|
|
43
22
|
readonly statusCode?: number | undefined;
|
|
44
23
|
constructor(message: string, statusCode?: number | undefined, code?: string);
|
|
45
24
|
}
|
|
46
|
-
/**
|
|
47
|
-
* Error thrown when API request fails
|
|
48
|
-
*/
|
|
49
25
|
export declare class ApiRequestError extends ApiError {
|
|
50
26
|
constructor(message: string, statusCode?: number);
|
|
51
27
|
}
|
|
52
|
-
/**
|
|
53
|
-
* Error thrown when API response is invalid
|
|
54
|
-
*/
|
|
55
|
-
export declare class InvalidResponseError extends ApiError {
|
|
56
|
-
constructor(message?: string);
|
|
57
|
-
}
|
|
58
|
-
/**
|
|
59
|
-
* Error thrown when a required parameter is missing
|
|
60
|
-
*/
|
|
61
28
|
export declare class MissingParameterError extends GatesError {
|
|
62
29
|
constructor(parameterName: string);
|
|
63
30
|
}
|
|
64
|
-
/**
|
|
65
|
-
* Error thrown when a parameter has an invalid value
|
|
66
|
-
*/
|
|
67
31
|
export declare class InvalidParameterError extends GatesError {
|
|
68
32
|
constructor(parameterName: string, reason?: string);
|
|
69
33
|
}
|
|
@@ -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"}
|
package/dist/errors/error.js
CHANGED
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
// src/errors/error.ts
|
|
2
|
-
/**
|
|
3
|
-
* Base error class for all Gates SDK errors
|
|
4
|
-
*/
|
|
5
1
|
export class GatesError extends Error {
|
|
6
2
|
code;
|
|
7
3
|
constructor(message, code) {
|
|
@@ -11,9 +7,6 @@ export class GatesError extends Error {
|
|
|
11
7
|
Object.setPrototypeOf(this, GatesError.prototype);
|
|
12
8
|
}
|
|
13
9
|
}
|
|
14
|
-
/**
|
|
15
|
-
* Base error class for authentication-related errors
|
|
16
|
-
*/
|
|
17
10
|
export class AuthenticationError extends GatesError {
|
|
18
11
|
constructor(message, code) {
|
|
19
12
|
super(message, code);
|
|
@@ -21,39 +14,27 @@ export class AuthenticationError extends GatesError {
|
|
|
21
14
|
Object.setPrototypeOf(this, AuthenticationError.prototype);
|
|
22
15
|
}
|
|
23
16
|
}
|
|
24
|
-
/**
|
|
25
|
-
* Error thrown when a token has expired
|
|
26
|
-
*/
|
|
27
17
|
export class TokenExpiredError extends AuthenticationError {
|
|
28
|
-
constructor(message = "Token
|
|
18
|
+
constructor(message = "Token has expired") {
|
|
29
19
|
super(message, "TOKEN_EXPIRED");
|
|
30
20
|
this.name = "TokenExpiredError";
|
|
31
21
|
Object.setPrototypeOf(this, TokenExpiredError.prototype);
|
|
32
22
|
}
|
|
33
23
|
}
|
|
34
|
-
/**
|
|
35
|
-
* Error thrown when a token is invalid
|
|
36
|
-
*/
|
|
37
24
|
export class InvalidTokenError extends AuthenticationError {
|
|
38
|
-
constructor(message = "
|
|
25
|
+
constructor(message = "Invalid token") {
|
|
39
26
|
super(message, "INVALID_TOKEN");
|
|
40
27
|
this.name = "InvalidTokenError";
|
|
41
28
|
Object.setPrototypeOf(this, InvalidTokenError.prototype);
|
|
42
29
|
}
|
|
43
30
|
}
|
|
44
|
-
/**
|
|
45
|
-
* Error thrown when authorization header is missing
|
|
46
|
-
*/
|
|
47
31
|
export class MissingAuthorizationError extends AuthenticationError {
|
|
48
|
-
constructor(message = "
|
|
32
|
+
constructor(message = "Authorization header is missing") {
|
|
49
33
|
super(message, "MISSING_AUTHORIZATION");
|
|
50
34
|
this.name = "MissingAuthorizationError";
|
|
51
35
|
Object.setPrototypeOf(this, MissingAuthorizationError.prototype);
|
|
52
36
|
}
|
|
53
37
|
}
|
|
54
|
-
/**
|
|
55
|
-
* Error thrown when user is not a member of required group
|
|
56
|
-
*/
|
|
57
38
|
export class UnauthorizedGroupError extends AuthenticationError {
|
|
58
39
|
requiredGroups;
|
|
59
40
|
constructor(message, requiredGroups) {
|
|
@@ -63,9 +44,6 @@ export class UnauthorizedGroupError extends AuthenticationError {
|
|
|
63
44
|
Object.setPrototypeOf(this, UnauthorizedGroupError.prototype);
|
|
64
45
|
}
|
|
65
46
|
}
|
|
66
|
-
/**
|
|
67
|
-
* Base error class for API-related errors
|
|
68
|
-
*/
|
|
69
47
|
export class ApiError extends GatesError {
|
|
70
48
|
statusCode;
|
|
71
49
|
constructor(message, statusCode, code) {
|
|
@@ -75,9 +53,6 @@ export class ApiError extends GatesError {
|
|
|
75
53
|
Object.setPrototypeOf(this, ApiError.prototype);
|
|
76
54
|
}
|
|
77
55
|
}
|
|
78
|
-
/**
|
|
79
|
-
* Error thrown when API request fails
|
|
80
|
-
*/
|
|
81
56
|
export class ApiRequestError extends ApiError {
|
|
82
57
|
constructor(message, statusCode) {
|
|
83
58
|
super(message, statusCode, "API_REQUEST_ERROR");
|
|
@@ -85,34 +60,18 @@ export class ApiRequestError extends ApiError {
|
|
|
85
60
|
Object.setPrototypeOf(this, ApiRequestError.prototype);
|
|
86
61
|
}
|
|
87
62
|
}
|
|
88
|
-
/**
|
|
89
|
-
* Error thrown when API response is invalid
|
|
90
|
-
*/
|
|
91
|
-
export class InvalidResponseError extends ApiError {
|
|
92
|
-
constructor(message = "Formato de resposta da API inválido") {
|
|
93
|
-
super(message, undefined, "INVALID_RESPONSE");
|
|
94
|
-
this.name = "InvalidResponseError";
|
|
95
|
-
Object.setPrototypeOf(this, InvalidResponseError.prototype);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
/**
|
|
99
|
-
* Error thrown when a required parameter is missing
|
|
100
|
-
*/
|
|
101
63
|
export class MissingParameterError extends GatesError {
|
|
102
64
|
constructor(parameterName) {
|
|
103
|
-
super(`
|
|
65
|
+
super(`Missing required parameter: ${parameterName}`, "MISSING_PARAMETER");
|
|
104
66
|
this.name = "MissingParameterError";
|
|
105
67
|
Object.setPrototypeOf(this, MissingParameterError.prototype);
|
|
106
68
|
}
|
|
107
69
|
}
|
|
108
|
-
/**
|
|
109
|
-
* Error thrown when a parameter has an invalid value
|
|
110
|
-
*/
|
|
111
70
|
export class InvalidParameterError extends GatesError {
|
|
112
71
|
constructor(parameterName, reason) {
|
|
113
72
|
const message = reason
|
|
114
|
-
? `
|
|
115
|
-
: `
|
|
73
|
+
? `Invalid parameter '${parameterName}': ${reason}`
|
|
74
|
+
: `Invalid parameter: ${parameterName}`;
|
|
116
75
|
super(message, "INVALID_PARAMETER");
|
|
117
76
|
this.name = "InvalidParameterError";
|
|
118
77
|
Object.setPrototypeOf(this, InvalidParameterError.prototype);
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export type { GatesUser
|
|
2
|
-
export
|
|
3
|
-
export {
|
|
4
|
-
export {
|
|
5
|
-
export { GatesError, AuthenticationError, TokenExpiredError, InvalidTokenError, MissingAuthorizationError, UnauthorizedGroupError, ApiError, ApiRequestError,
|
|
1
|
+
export type { GatesUser, GatesRole } from "./models/user.js";
|
|
2
|
+
export { AuthService, type VerifyOptions } from "./services/auth-service.js";
|
|
3
|
+
export { GatesAdminService, type GatesAdminConfig, type CreateUserParams, type CreateUserResponse, type UpdateUserParams, } from "./services/admin-service.js";
|
|
4
|
+
export { extractToken, authenticate, authorize, handleAuth, type AuthHandlerConfig, } from "./auth/middleware.js";
|
|
5
|
+
export { GatesError, AuthenticationError, TokenExpiredError, InvalidTokenError, MissingAuthorizationError, UnauthorizedGroupError, ApiError, ApiRequestError, MissingParameterError, InvalidParameterError, } from "./errors/error.js";
|
|
6
6
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAG7D,OAAO,EAAE,WAAW,EAAE,KAAK,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAE7E,OAAO,EACL,iBAAiB,EACjB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,GACtB,MAAM,6BAA6B,CAAC;AAGrC,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,SAAS,EACT,UAAU,EACV,KAAK,iBAAiB,GACvB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EACL,UAAU,EACV,mBAAmB,EACnB,iBAAiB,EACjB,iBAAiB,EACjB,yBAAyB,EACzB,sBAAsB,EACtB,QAAQ,EACR,eAAe,EACf,qBAAqB,EACrB,qBAAqB,GACtB,MAAM,mBAAmB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,14 +1,7 @@
|
|
|
1
|
-
// Main exports for Gates SDK
|
|
2
1
|
// Services
|
|
3
|
-
export {
|
|
4
|
-
export {
|
|
2
|
+
export { AuthService } from "./services/auth-service.js";
|
|
3
|
+
export { GatesAdminService, } from "./services/admin-service.js";
|
|
4
|
+
// Middleware
|
|
5
|
+
export { extractToken, authenticate, authorize, handleAuth, } from "./auth/middleware.js";
|
|
5
6
|
// Errors
|
|
6
|
-
export {
|
|
7
|
-
// Base errors
|
|
8
|
-
GatesError,
|
|
9
|
-
// Authentication errors
|
|
10
|
-
AuthenticationError, TokenExpiredError, InvalidTokenError, MissingAuthorizationError, UnauthorizedGroupError,
|
|
11
|
-
// API errors
|
|
12
|
-
ApiError, ApiRequestError, InvalidResponseError,
|
|
13
|
-
// Parameter errors
|
|
14
|
-
MissingParameterError, InvalidParameterError, } from "./errors/error.js";
|
|
7
|
+
export { GatesError, AuthenticationError, TokenExpiredError, InvalidTokenError, MissingAuthorizationError, UnauthorizedGroupError, ApiError, ApiRequestError, MissingParameterError, InvalidParameterError, } from "./errors/error.js";
|
package/dist/models/user.d.ts
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
* Tipagem base do payload que sai do Cognito.
|
|
3
|
-
* Você pode estender com claims próprias (ex.: permissions, system_access).
|
|
4
|
-
*/
|
|
1
|
+
export type GatesRole = "INTERNAL_ADMIN" | "INTERNAL_USER" | "CLIENT_ADMIN" | "CLIENT_USER";
|
|
5
2
|
export type GatesUser = {
|
|
6
3
|
user_id: string;
|
|
7
|
-
email
|
|
8
|
-
name
|
|
9
|
-
role
|
|
4
|
+
email?: string;
|
|
5
|
+
name?: string;
|
|
6
|
+
role?: string;
|
|
7
|
+
groups: string[];
|
|
8
|
+
token_use: "access" | "id";
|
|
10
9
|
exp: number;
|
|
11
10
|
iat: number;
|
|
12
11
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"user.d.ts","sourceRoot":"","sources":["../../src/models/user.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"user.d.ts","sourceRoot":"","sources":["../../src/models/user.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,SAAS,GACjB,gBAAgB,GAChB,eAAe,GACf,cAAc,GACd,aAAa,CAAC;AAElB,MAAM,MAAM,SAAS,GAAG;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;CACb,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { GatesRole } from "../models/user.js";
|
|
2
|
+
export type GatesAdminConfig = {
|
|
3
|
+
baseUrl: string;
|
|
4
|
+
};
|
|
5
|
+
export type CreateUserParams = {
|
|
6
|
+
email: string;
|
|
7
|
+
name: string;
|
|
8
|
+
role: GatesRole;
|
|
9
|
+
client: string;
|
|
10
|
+
};
|
|
11
|
+
export type CreateUserResponse = {
|
|
12
|
+
sub: string;
|
|
13
|
+
};
|
|
14
|
+
export type UpdateUserParams = {
|
|
15
|
+
user_id: string;
|
|
16
|
+
clients_to_add?: string[];
|
|
17
|
+
clients_to_remove?: string[];
|
|
18
|
+
};
|
|
19
|
+
export declare class GatesAdminService {
|
|
20
|
+
private readonly baseUrl;
|
|
21
|
+
constructor(config: GatesAdminConfig);
|
|
22
|
+
createUser(idToken: string, params: CreateUserParams): Promise<CreateUserResponse>;
|
|
23
|
+
updateUser(idToken: string, params: UpdateUserParams): Promise<void>;
|
|
24
|
+
private request;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=admin-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin-service.d.ts","sourceRoot":"","sources":["../../src/services/admin-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAO9C,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,SAAS,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC9B,CAAC;AASF,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAErB,MAAM,EAAE,gBAAgB;IAO9B,UAAU,CACd,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,gBAAgB,GACvB,OAAO,CAAC,kBAAkB,CAAC;IAgDxB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;YAgB5D,OAAO;CAmCtB"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { MissingParameterError, InvalidParameterError, ApiRequestError, } from "../errors/error.js";
|
|
2
|
+
const VALID_ROLES = [
|
|
3
|
+
"INTERNAL_ADMIN",
|
|
4
|
+
"INTERNAL_USER",
|
|
5
|
+
"CLIENT_ADMIN",
|
|
6
|
+
"CLIENT_USER",
|
|
7
|
+
];
|
|
8
|
+
export class GatesAdminService {
|
|
9
|
+
baseUrl;
|
|
10
|
+
constructor(config) {
|
|
11
|
+
if (!config.baseUrl || config.baseUrl.trim().length === 0) {
|
|
12
|
+
throw new MissingParameterError("baseUrl");
|
|
13
|
+
}
|
|
14
|
+
this.baseUrl = config.baseUrl.replace(/\/$/, "");
|
|
15
|
+
}
|
|
16
|
+
async createUser(idToken, params) {
|
|
17
|
+
if (!idToken) {
|
|
18
|
+
throw new MissingParameterError("idToken");
|
|
19
|
+
}
|
|
20
|
+
if (!params.email || params.email.trim().length === 0) {
|
|
21
|
+
throw new MissingParameterError("email");
|
|
22
|
+
}
|
|
23
|
+
if (!params.name || params.name.trim().length === 0) {
|
|
24
|
+
throw new MissingParameterError("name");
|
|
25
|
+
}
|
|
26
|
+
if (!params.role) {
|
|
27
|
+
throw new MissingParameterError("role");
|
|
28
|
+
}
|
|
29
|
+
if (!VALID_ROLES.includes(params.role)) {
|
|
30
|
+
throw new InvalidParameterError("role", `must be one of: ${VALID_ROLES.join(", ")}`);
|
|
31
|
+
}
|
|
32
|
+
if (!params.client || params.client.trim().length === 0) {
|
|
33
|
+
throw new MissingParameterError("client");
|
|
34
|
+
}
|
|
35
|
+
const response = await this.request("POST", "/create-user", idToken, {
|
|
36
|
+
email: params.email,
|
|
37
|
+
name: params.name,
|
|
38
|
+
role: params.role,
|
|
39
|
+
});
|
|
40
|
+
const data = (await response.json());
|
|
41
|
+
if (!data.sub) {
|
|
42
|
+
throw new ApiRequestError("Response missing 'sub' field");
|
|
43
|
+
}
|
|
44
|
+
await this.updateUser(idToken, {
|
|
45
|
+
user_id: data.sub,
|
|
46
|
+
clients_to_add: [params.client],
|
|
47
|
+
});
|
|
48
|
+
return data;
|
|
49
|
+
}
|
|
50
|
+
async updateUser(idToken, params) {
|
|
51
|
+
if (!idToken) {
|
|
52
|
+
throw new MissingParameterError("idToken");
|
|
53
|
+
}
|
|
54
|
+
if (!params.user_id || params.user_id.trim().length === 0) {
|
|
55
|
+
throw new MissingParameterError("user_id");
|
|
56
|
+
}
|
|
57
|
+
await this.request("PUT", "/update-user", idToken, {
|
|
58
|
+
user_id: params.user_id,
|
|
59
|
+
clients_to_add: params.clients_to_add,
|
|
60
|
+
clients_to_remove: params.clients_to_remove,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
async request(method, path, idToken, body) {
|
|
64
|
+
let response;
|
|
65
|
+
try {
|
|
66
|
+
response = await fetch(`${this.baseUrl}${path}`, {
|
|
67
|
+
method,
|
|
68
|
+
headers: {
|
|
69
|
+
"Content-Type": "application/json",
|
|
70
|
+
Authorization: `Bearer ${idToken}`,
|
|
71
|
+
},
|
|
72
|
+
body: JSON.stringify(body),
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
const message = error instanceof Error ? error.message : "Unknown network error";
|
|
77
|
+
throw new ApiRequestError(`Failed to reach Gates API: ${message}`);
|
|
78
|
+
}
|
|
79
|
+
if (!response.ok) {
|
|
80
|
+
let detail;
|
|
81
|
+
try {
|
|
82
|
+
const errorBody = (await response.json());
|
|
83
|
+
detail = errorBody.message ?? response.statusText;
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
detail = response.statusText;
|
|
87
|
+
}
|
|
88
|
+
throw new ApiRequestError(`Gates API error: ${detail}`, response.status);
|
|
89
|
+
}
|
|
90
|
+
return response;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -2,17 +2,14 @@ import { GatesUser } from "../models/user.js";
|
|
|
2
2
|
export type VerifyOptions = {
|
|
3
3
|
region: string;
|
|
4
4
|
userPoolId: string;
|
|
5
|
-
|
|
6
|
-
requiredGroup?: string | string[];
|
|
5
|
+
clientId: string;
|
|
7
6
|
};
|
|
8
|
-
export declare class
|
|
7
|
+
export declare class AuthService {
|
|
9
8
|
private readonly region;
|
|
10
9
|
private readonly userPoolId;
|
|
11
|
-
private readonly
|
|
12
|
-
|
|
13
|
-
constructor(region: string, userPoolId: string, audience: string, requiredGroup?: string | string[]);
|
|
10
|
+
private readonly clientId;
|
|
11
|
+
constructor(region: string, userPoolId: string, clientId: string);
|
|
14
12
|
private get issuer();
|
|
15
|
-
isMemberOf(groups?: string[]): boolean;
|
|
16
13
|
verifyToken(token: string): Promise<GatesUser>;
|
|
17
14
|
}
|
|
18
15
|
//# sourceMappingURL=auth-service.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth-service.d.ts","sourceRoot":"","sources":["../../src/services/auth-service.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"auth-service.d.ts","sourceRoot":"","sources":["../../src/services/auth-service.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAQ9C,MAAM,MAAM,aAAa,GAAG;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;gBAEtB,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;IAiChE,OAAO,KAAK,MAAM,GAEjB;IAEK,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;CAqFrD"}
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { jwtVerify, errors as joseErrors } from "jose";
|
|
2
2
|
import { getJwks } from "../cache/jwks-cache.js";
|
|
3
|
-
import { InvalidParameterError, MissingParameterError, TokenExpiredError, InvalidTokenError,
|
|
4
|
-
export class
|
|
3
|
+
import { InvalidParameterError, MissingParameterError, TokenExpiredError, InvalidTokenError, } from "../errors/error.js";
|
|
4
|
+
export class AuthService {
|
|
5
5
|
region;
|
|
6
6
|
userPoolId;
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
constructor(region, userPoolId, audience, requiredGroup) {
|
|
7
|
+
clientId;
|
|
8
|
+
constructor(region, userPoolId, clientId) {
|
|
10
9
|
if (!region || typeof region !== "string" || region.trim().length === 0) {
|
|
11
10
|
throw new MissingParameterError("region");
|
|
12
11
|
}
|
|
@@ -15,35 +14,21 @@ export class GatesAuthService {
|
|
|
15
14
|
userPoolId.trim().length === 0) {
|
|
16
15
|
throw new MissingParameterError("userPoolId");
|
|
17
16
|
}
|
|
18
|
-
if (!
|
|
19
|
-
typeof
|
|
20
|
-
|
|
21
|
-
throw new MissingParameterError("
|
|
17
|
+
if (!clientId ||
|
|
18
|
+
typeof clientId !== "string" ||
|
|
19
|
+
clientId.trim().length === 0) {
|
|
20
|
+
throw new MissingParameterError("clientId");
|
|
22
21
|
}
|
|
23
|
-
// Validar formato do userPoolId (deve seguir padrão AWS)
|
|
24
22
|
if (!/^[a-zA-Z0-9_-]+$/.test(userPoolId)) {
|
|
25
|
-
throw new InvalidParameterError("userPoolId", "
|
|
23
|
+
throw new InvalidParameterError("userPoolId", "must follow AWS format (alphanumeric, hyphens, and underscores only)");
|
|
26
24
|
}
|
|
27
25
|
this.region = region;
|
|
28
26
|
this.userPoolId = userPoolId;
|
|
29
|
-
this.
|
|
30
|
-
this.requiredGroup = requiredGroup;
|
|
27
|
+
this.clientId = clientId;
|
|
31
28
|
}
|
|
32
29
|
get issuer() {
|
|
33
30
|
return `https://cognito-idp.${this.region}.amazonaws.com/${this.userPoolId}`;
|
|
34
31
|
}
|
|
35
|
-
isMemberOf(groups = []) {
|
|
36
|
-
if (!Array.isArray(groups)) {
|
|
37
|
-
return false;
|
|
38
|
-
}
|
|
39
|
-
if (!this.requiredGroup) {
|
|
40
|
-
return true;
|
|
41
|
-
}
|
|
42
|
-
const requiredGroups = Array.isArray(this.requiredGroup)
|
|
43
|
-
? this.requiredGroup
|
|
44
|
-
: [this.requiredGroup];
|
|
45
|
-
return groups.some((g) => requiredGroups.includes(g));
|
|
46
|
-
}
|
|
47
32
|
async verifyToken(token) {
|
|
48
33
|
if (!token) {
|
|
49
34
|
throw new MissingParameterError("token");
|
|
@@ -52,47 +37,48 @@ export class GatesAuthService {
|
|
|
52
37
|
const jwks = getJwks(this.region, this.userPoolId);
|
|
53
38
|
const { payload } = await jwtVerify(token, jwks, {
|
|
54
39
|
issuer: this.issuer,
|
|
55
|
-
audience: this.audience,
|
|
56
40
|
});
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
41
|
+
const tokenUse = payload.token_use;
|
|
42
|
+
if (tokenUse !== "access" && tokenUse !== "id") {
|
|
43
|
+
throw new InvalidTokenError(`Unsupported token_use: expected "access" or "id", got "${tokenUse}"`);
|
|
44
|
+
}
|
|
45
|
+
if (tokenUse === "access") {
|
|
46
|
+
const clientId = payload.client_id;
|
|
47
|
+
if (clientId !== this.clientId) {
|
|
48
|
+
throw new InvalidTokenError("Token client_id does not match the expected clientId");
|
|
64
49
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
const aud = payload.aud;
|
|
53
|
+
const audValue = Array.isArray(aud) ? aud[0] : aud;
|
|
54
|
+
if (audValue !== this.clientId) {
|
|
55
|
+
throw new InvalidTokenError("Token audience does not match the expected clientId");
|
|
69
56
|
}
|
|
70
57
|
}
|
|
71
|
-
|
|
58
|
+
const groups = payload["cognito:groups"] ?? [];
|
|
72
59
|
const user = {
|
|
73
60
|
user_id: payload.sub,
|
|
74
61
|
email: payload.email,
|
|
75
62
|
name: payload.name,
|
|
76
63
|
role: payload["custom:general_role"],
|
|
64
|
+
groups,
|
|
65
|
+
token_use: tokenUse,
|
|
77
66
|
exp: payload.exp,
|
|
78
67
|
iat: payload.iat,
|
|
79
68
|
};
|
|
80
69
|
return user;
|
|
81
70
|
}
|
|
82
71
|
catch (error) {
|
|
83
|
-
|
|
84
|
-
if (error instanceof UnauthorizedGroupError ||
|
|
72
|
+
if (error instanceof InvalidTokenError ||
|
|
85
73
|
error instanceof MissingParameterError) {
|
|
86
74
|
throw error;
|
|
87
75
|
}
|
|
88
|
-
// Handle jose-specific errors
|
|
89
76
|
if (error instanceof joseErrors.JWTExpired) {
|
|
90
|
-
throw new TokenExpiredError(
|
|
77
|
+
throw new TokenExpiredError();
|
|
91
78
|
}
|
|
92
79
|
if (error instanceof joseErrors.JWTInvalid) {
|
|
93
|
-
throw new InvalidTokenError("
|
|
80
|
+
throw new InvalidTokenError("Invalid or malformed token");
|
|
94
81
|
}
|
|
95
|
-
// Handle other jose errors
|
|
96
82
|
if (error instanceof Error) {
|
|
97
83
|
if (error.message.includes("expired")) {
|
|
98
84
|
throw new TokenExpiredError(error.message);
|
|
@@ -101,9 +87,9 @@ export class GatesAuthService {
|
|
|
101
87
|
error.message.includes("invalid")) {
|
|
102
88
|
throw new InvalidTokenError(error.message);
|
|
103
89
|
}
|
|
104
|
-
throw new InvalidTokenError(`
|
|
90
|
+
throw new InvalidTokenError(`Token verification failed: ${error.message}`);
|
|
105
91
|
}
|
|
106
|
-
throw new InvalidTokenError("
|
|
92
|
+
throw new InvalidTokenError("Token verification failed");
|
|
107
93
|
}
|
|
108
94
|
}
|
|
109
95
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export type ClientCredentialsConfig = {
|
|
2
|
+
domain: string;
|
|
3
|
+
clientId: string;
|
|
4
|
+
clientSecret: string;
|
|
5
|
+
scopes?: string[];
|
|
6
|
+
};
|
|
7
|
+
export type ClientToken = {
|
|
8
|
+
access_token: string;
|
|
9
|
+
expires_in: number;
|
|
10
|
+
token_type: string;
|
|
11
|
+
};
|
|
12
|
+
export declare class GatesClientAuth {
|
|
13
|
+
private readonly tokenEndpoint;
|
|
14
|
+
private readonly clientId;
|
|
15
|
+
private readonly clientSecret;
|
|
16
|
+
private readonly scopes;
|
|
17
|
+
private cachedToken;
|
|
18
|
+
constructor(config: ClientCredentialsConfig);
|
|
19
|
+
getAccessToken(): Promise<string>;
|
|
20
|
+
clearCache(): void;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=client-auth.d.ts.map
|