@intelicity/gates-sdk 0.1.5 → 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.
@@ -1,19 +1,19 @@
1
- // src/errors/error.ts
2
- /**
3
- * Base error class for authentication-related errors
4
- */
5
- export class AuthenticationError extends Error {
1
+ export class GatesError extends Error {
6
2
  code;
7
3
  constructor(message, code) {
8
4
  super(message);
9
5
  this.code = code;
6
+ this.name = "GatesError";
7
+ Object.setPrototypeOf(this, GatesError.prototype);
8
+ }
9
+ }
10
+ export class AuthenticationError extends GatesError {
11
+ constructor(message, code) {
12
+ super(message, code);
10
13
  this.name = "AuthenticationError";
11
14
  Object.setPrototypeOf(this, AuthenticationError.prototype);
12
15
  }
13
16
  }
14
- /**
15
- * Error thrown when a token has expired
16
- */
17
17
  export class TokenExpiredError extends AuthenticationError {
18
18
  constructor(message = "Token has expired") {
19
19
  super(message, "TOKEN_EXPIRED");
@@ -21,9 +21,6 @@ export class TokenExpiredError extends AuthenticationError {
21
21
  Object.setPrototypeOf(this, TokenExpiredError.prototype);
22
22
  }
23
23
  }
24
- /**
25
- * Error thrown when a token is invalid
26
- */
27
24
  export class InvalidTokenError extends AuthenticationError {
28
25
  constructor(message = "Invalid token") {
29
26
  super(message, "INVALID_TOKEN");
@@ -31,13 +28,52 @@ export class InvalidTokenError extends AuthenticationError {
31
28
  Object.setPrototypeOf(this, InvalidTokenError.prototype);
32
29
  }
33
30
  }
34
- /**
35
- * Error thrown when authorization header is missing
36
- */
37
31
  export class MissingAuthorizationError extends AuthenticationError {
38
- constructor(message = "Missing Authorization header") {
32
+ constructor(message = "Authorization header is missing") {
39
33
  super(message, "MISSING_AUTHORIZATION");
40
34
  this.name = "MissingAuthorizationError";
41
35
  Object.setPrototypeOf(this, MissingAuthorizationError.prototype);
42
36
  }
43
37
  }
38
+ export class UnauthorizedGroupError extends AuthenticationError {
39
+ requiredGroups;
40
+ constructor(message, requiredGroups) {
41
+ super(message, "UNAUTHORIZED_GROUP");
42
+ this.requiredGroups = requiredGroups;
43
+ this.name = "UnauthorizedGroupError";
44
+ Object.setPrototypeOf(this, UnauthorizedGroupError.prototype);
45
+ }
46
+ }
47
+ export class ApiError extends GatesError {
48
+ statusCode;
49
+ constructor(message, statusCode, code) {
50
+ super(message, code);
51
+ this.statusCode = statusCode;
52
+ this.name = "ApiError";
53
+ Object.setPrototypeOf(this, ApiError.prototype);
54
+ }
55
+ }
56
+ export class ApiRequestError extends ApiError {
57
+ constructor(message, statusCode) {
58
+ super(message, statusCode, "API_REQUEST_ERROR");
59
+ this.name = "ApiRequestError";
60
+ Object.setPrototypeOf(this, ApiRequestError.prototype);
61
+ }
62
+ }
63
+ export class MissingParameterError extends GatesError {
64
+ constructor(parameterName) {
65
+ super(`Missing required parameter: ${parameterName}`, "MISSING_PARAMETER");
66
+ this.name = "MissingParameterError";
67
+ Object.setPrototypeOf(this, MissingParameterError.prototype);
68
+ }
69
+ }
70
+ export class InvalidParameterError extends GatesError {
71
+ constructor(parameterName, reason) {
72
+ const message = reason
73
+ ? `Invalid parameter '${parameterName}': ${reason}`
74
+ : `Invalid parameter: ${parameterName}`;
75
+ super(message, "INVALID_PARAMETER");
76
+ this.name = "InvalidParameterError";
77
+ Object.setPrototypeOf(this, InvalidParameterError.prototype);
78
+ }
79
+ }
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- export type { GatesUser as GatesUser } from "./models/user.js";
2
- export type { UserProfile as Profile, ProfileAttribute, } from "./models/profile.js";
3
- export { GatesUserService as UserService, type UserListResponse, type GetAllUsersOptions, } from "./services/user-service.js";
4
- export { GatesAuthService as AuthService, type VerifyOptions, } from "./services/auth-service.js";
5
- export { AuthenticationError, TokenExpiredError, InvalidTokenError, MissingAuthorizationError, } from "./errors/error.js";
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
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EAAE,SAAS,IAAI,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC/D,YAAY,EACV,WAAW,IAAI,OAAO,EACtB,gBAAgB,GACjB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,gBAAgB,IAAI,WAAW,EAC/B,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,GACxB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,gBAAgB,IAAI,WAAW,EAC/B,KAAK,aAAa,GACnB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EACjB,iBAAiB,EACjB,yBAAyB,GAC1B,MAAM,mBAAmB,CAAC"}
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,3 +1,7 @@
1
- export { GatesUserService as UserService, } from "./services/user-service.js";
2
- export { GatesAuthService as AuthService, } from "./services/auth-service.js";
3
- export { AuthenticationError, TokenExpiredError, InvalidTokenError, MissingAuthorizationError, } from "./errors/error.js";
1
+ // Services
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";
6
+ // Errors
7
+ export { GatesError, AuthenticationError, TokenExpiredError, InvalidTokenError, MissingAuthorizationError, UnauthorizedGroupError, ApiError, ApiRequestError, MissingParameterError, InvalidParameterError, } from "./errors/error.js";
@@ -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: string;
8
- name: string;
9
- role: string;
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;;;GAGG;AACH,MAAM,MAAM,SAAS,GAAG;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;CACb,CAAC"}
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
- audience: string;
6
- requiredGroup?: string | string[];
5
+ clientId: string;
7
6
  };
8
- export declare class GatesAuthService {
7
+ export declare class AuthService {
9
8
  private readonly region;
10
9
  private readonly userPoolId;
11
- private readonly audience;
12
- private readonly requiredGroup?;
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;AAE9C,MAAM,MAAM,aAAa,GAAG;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;CACnC,CAAC;AAEF,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAoB;gBAGjD,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE;IAiCnC,OAAO,KAAK,MAAM,GAEjB;IAED,UAAU,CAAC,MAAM,GAAE,MAAM,EAAO,GAAG,OAAO;IAgBpC,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;CAiDrD"}
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,80 +1,95 @@
1
- import { jwtVerify } from "jose";
1
+ import { jwtVerify, errors as joseErrors } from "jose";
2
2
  import { getJwks } from "../cache/jwks-cache.js";
3
- export class GatesAuthService {
3
+ import { InvalidParameterError, MissingParameterError, TokenExpiredError, InvalidTokenError, } from "../errors/error.js";
4
+ export class AuthService {
4
5
  region;
5
6
  userPoolId;
6
- audience;
7
- requiredGroup;
8
- constructor(region, userPoolId, audience, requiredGroup) {
7
+ clientId;
8
+ constructor(region, userPoolId, clientId) {
9
9
  if (!region || typeof region !== "string" || region.trim().length === 0) {
10
- throw new Error("Region é obrigatória e deve ser uma string válida");
10
+ throw new MissingParameterError("region");
11
11
  }
12
12
  if (!userPoolId ||
13
13
  typeof userPoolId !== "string" ||
14
14
  userPoolId.trim().length === 0) {
15
- throw new Error("UserPoolId é obrigatório e deve ser uma string válida");
15
+ throw new MissingParameterError("userPoolId");
16
16
  }
17
- if (!audience ||
18
- typeof audience !== "string" ||
19
- audience.trim().length === 0) {
20
- throw new Error("Audience é obrigatória e deve ser uma string válida");
17
+ if (!clientId ||
18
+ typeof clientId !== "string" ||
19
+ clientId.trim().length === 0) {
20
+ throw new MissingParameterError("clientId");
21
21
  }
22
- // Validar formato do userPoolId (deve seguir padrão AWS)
23
22
  if (!/^[a-zA-Z0-9_-]+$/.test(userPoolId)) {
24
- throw new Error("UserPoolId possui formato inválido");
23
+ throw new InvalidParameterError("userPoolId", "must follow AWS format (alphanumeric, hyphens, and underscores only)");
25
24
  }
26
25
  this.region = region;
27
26
  this.userPoolId = userPoolId;
28
- this.audience = audience;
29
- this.requiredGroup = requiredGroup;
27
+ this.clientId = clientId;
30
28
  }
31
29
  get issuer() {
32
30
  return `https://cognito-idp.${this.region}.amazonaws.com/${this.userPoolId}`;
33
31
  }
34
- isMemberOf(groups = []) {
35
- if (!Array.isArray(groups)) {
36
- return false;
37
- }
38
- if (!this.requiredGroup) {
39
- return true;
40
- }
41
- const requiredGroups = Array.isArray(this.requiredGroup)
42
- ? this.requiredGroup
43
- : [this.requiredGroup];
44
- return groups.some((g) => requiredGroups.includes(g));
45
- }
46
32
  async verifyToken(token) {
47
33
  if (!token) {
48
- throw new Error("Token não fornecido");
34
+ throw new MissingParameterError("token");
49
35
  }
50
- const jwks = getJwks(this.region, this.userPoolId);
51
- const { payload } = await jwtVerify(token, jwks, {
52
- issuer: this.issuer,
53
- audience: this.audience,
54
- });
55
- if (this.requiredGroup) {
56
- const userGroups = payload["cognito:groups"];
57
- if (!userGroups || !Array.isArray(userGroups)) {
58
- throw new Error("Usuário não pertence ao sistema");
36
+ try {
37
+ const jwks = getJwks(this.region, this.userPoolId);
38
+ const { payload } = await jwtVerify(token, jwks, {
39
+ issuer: this.issuer,
40
+ });
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");
49
+ }
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");
56
+ }
57
+ }
58
+ const groups = payload["cognito:groups"] ?? [];
59
+ const user = {
60
+ user_id: payload.sub,
61
+ email: payload.email,
62
+ name: payload.name,
63
+ role: payload["custom:general_role"],
64
+ groups,
65
+ token_use: tokenUse,
66
+ exp: payload.exp,
67
+ iat: payload.iat,
68
+ };
69
+ return user;
70
+ }
71
+ catch (error) {
72
+ if (error instanceof InvalidTokenError ||
73
+ error instanceof MissingParameterError) {
74
+ throw error;
75
+ }
76
+ if (error instanceof joseErrors.JWTExpired) {
77
+ throw new TokenExpiredError();
78
+ }
79
+ if (error instanceof joseErrors.JWTInvalid) {
80
+ throw new InvalidTokenError("Invalid or malformed token");
59
81
  }
60
- const requiredGroups = Array.isArray(this.requiredGroup)
61
- ? this.requiredGroup
62
- : [this.requiredGroup];
63
- // Verifica se o usuário tem pelo menos um dos grupos obrigatórios
64
- const hasRequiredGroup = requiredGroups.some((group) => userGroups.includes(group));
65
- if (!hasRequiredGroup) {
66
- throw new Error(`Usuário deve ser membro de um dos seguintes sistemas: ${requiredGroups.join(", ")}`);
82
+ if (error instanceof Error) {
83
+ if (error.message.includes("expired")) {
84
+ throw new TokenExpiredError(error.message);
85
+ }
86
+ if (error.message.includes("signature") ||
87
+ error.message.includes("invalid")) {
88
+ throw new InvalidTokenError(error.message);
89
+ }
90
+ throw new InvalidTokenError(`Token verification failed: ${error.message}`);
67
91
  }
92
+ throw new InvalidTokenError("Token verification failed");
68
93
  }
69
- // Mapear o payload do Cognito para o formato do GatesUser
70
- const user = {
71
- user_id: payload.sub,
72
- email: payload.email,
73
- name: payload.name,
74
- role: payload["custom:general_role"],
75
- exp: payload.exp,
76
- iat: payload.iat,
77
- };
78
- return user;
79
94
  }
80
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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-auth.d.ts","sourceRoot":"","sources":["../../src/services/client-auth.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,uBAAuB,GAAG;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAW;IAClC,OAAO,CAAC,WAAW,CAAqD;gBAE5D,MAAM,EAAE,uBAAuB;IAkBrC,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC;IAiEvC,UAAU,IAAI,IAAI;CAGnB"}
@@ -0,0 +1,75 @@
1
+ import { MissingParameterError, ClientCredentialsError, } from "../errors/error.js";
2
+ export class GatesClientAuth {
3
+ tokenEndpoint;
4
+ clientId;
5
+ clientSecret;
6
+ scopes;
7
+ cachedToken = null;
8
+ constructor(config) {
9
+ if (!config.domain || config.domain.trim().length === 0) {
10
+ throw new MissingParameterError("domain");
11
+ }
12
+ if (!config.clientId || config.clientId.trim().length === 0) {
13
+ throw new MissingParameterError("clientId");
14
+ }
15
+ if (!config.clientSecret || config.clientSecret.trim().length === 0) {
16
+ throw new MissingParameterError("clientSecret");
17
+ }
18
+ const domain = config.domain.replace(/\/$/, "");
19
+ this.tokenEndpoint = `https://${domain}/oauth2/token`;
20
+ this.clientId = config.clientId;
21
+ this.clientSecret = config.clientSecret;
22
+ this.scopes = config.scopes ?? [];
23
+ }
24
+ async getAccessToken() {
25
+ if (this.cachedToken && Date.now() < this.cachedToken.expiresAt) {
26
+ return this.cachedToken.token;
27
+ }
28
+ const body = new URLSearchParams({
29
+ grant_type: "client_credentials",
30
+ });
31
+ if (this.scopes.length > 0) {
32
+ body.set("scope", this.scopes.join(" "));
33
+ }
34
+ const credentials = Buffer.from(`${this.clientId}:${this.clientSecret}`).toString("base64");
35
+ let response;
36
+ try {
37
+ response = await fetch(this.tokenEndpoint, {
38
+ method: "POST",
39
+ headers: {
40
+ "Content-Type": "application/x-www-form-urlencoded",
41
+ Authorization: `Basic ${credentials}`,
42
+ },
43
+ body: body.toString(),
44
+ });
45
+ }
46
+ catch (error) {
47
+ const message = error instanceof Error ? error.message : "Unknown network error";
48
+ throw new ClientCredentialsError(`Failed to reach token endpoint: ${message}`);
49
+ }
50
+ if (!response.ok) {
51
+ let detail;
52
+ try {
53
+ const errorBody = (await response.json());
54
+ detail = errorBody.error ?? response.statusText;
55
+ }
56
+ catch {
57
+ detail = response.statusText;
58
+ }
59
+ throw new ClientCredentialsError(`Token request failed (${response.status}): ${detail}`);
60
+ }
61
+ const data = (await response.json());
62
+ if (!data.access_token) {
63
+ throw new ClientCredentialsError("Token response missing access_token field");
64
+ }
65
+ const bufferMs = 30_000;
66
+ this.cachedToken = {
67
+ token: data.access_token,
68
+ expiresAt: Date.now() + data.expires_in * 1000 - bufferMs,
69
+ };
70
+ return data.access_token;
71
+ }
72
+ clearCache() {
73
+ this.cachedToken = null;
74
+ }
75
+ }
@@ -27,9 +27,9 @@ export declare class GatesUserService {
27
27
  getAllUsers(idToken: string): Promise<UserListResponse>;
28
28
  /**
29
29
  * Busca um usuário específico por ID
30
- * @param accessToken Token de autenticação
30
+ * @param idToken Token de autenticação
31
31
  * @returns Dados do usuário
32
32
  */
33
- login(accessToken: string): Promise<UserProfile>;
33
+ getProfile(idToken: string): Promise<UserProfile>;
34
34
  }
35
35
  //# sourceMappingURL=user-service.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"user-service.d.ts","sourceRoot":"","sources":["../../src/services/user-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAoB,MAAM,sBAAsB,CAAC;AAErE,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAgBD,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAyB;gBAE5C,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAQ3C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAExB;IAEF;;;;;OAKG;IACG,WAAW,CACf,OAAO,EAAE,MAAM,GAEd,OAAO,CAAC,gBAAgB,CAAC;IAiD5B;;;;OAIG;IACG,KAAK,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;CA2CvD"}
1
+ {"version":3,"file":"user-service.d.ts","sourceRoot":"","sources":["../../src/services/user-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAoB,MAAM,sBAAsB,CAAC;AAOrE,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAeD,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAyB;gBAE5C,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAQ3C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAExB;IAEF;;;;;OAKG;IACG,WAAW,CACf,OAAO,EAAE,MAAM,GAEd,OAAO,CAAC,gBAAgB,CAAC;IAqE5B;;;;OAIG;IACG,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;CAuExD"}