@hemia/auth-sdk 0.0.8 → 0.0.10

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,4 +1,4 @@
1
- import { BadRequestError, CustomHttpError, InternalServerError, Get, Req, Res, Post, HttpError } from '@hemia/common';
1
+ import { BadRequestError, CustomHttpError, InternalServerError, Get, Req, Res, Post, Controller, HttpError, METADATA_KEYS, ControllerRegistry } from '@hemia/common';
2
2
  import { HMNetworkServices } from '@hemia/network-services';
3
3
  import { JwtManager } from '@hemia/jwt-manager';
4
4
  import { randomBytes, createHash } from 'crypto';
@@ -178,10 +178,10 @@ let AuthService = class AuthService {
178
178
  if (response.status !== 200) {
179
179
  throw new CustomHttpError('Token exchange failed', response.status, 'token_exchange_failed');
180
180
  }
181
- if (!response.data.access_token) {
181
+ if (!response.data.data?.access_token) {
182
182
  throw new InternalServerError('No access token received from SSO', 'invalid_token_response');
183
183
  }
184
- const { access_token, refresh_token, id_token, expires_in, session_id } = response.data;
184
+ const { access_token, refresh_token, id_token, expires_in, session_id } = response.data.data;
185
185
  const sessionId = randomBytes(16).toString('hex');
186
186
  const sessionData = {
187
187
  accessToken: access_token,
@@ -266,12 +266,30 @@ let AuthService = class AuthService {
266
266
  if (!verify) {
267
267
  throw new SessionInvalidError();
268
268
  }
269
- const claims = this.jwtManager.decode(session.accessToken, true);
270
- if (!claims) {
269
+ const claimsAccess = this.jwtManager.decode(session.accessToken, true);
270
+ if (!claimsAccess) {
271
271
  throw new SessionInvalidError();
272
272
  }
273
+ const claimsId = this.jwtManager.decode(session.idToken, true);
273
274
  return {
274
- ...claims
275
+ aud: claimsAccess.aud,
276
+ iss: claimsAccess.iss || '',
277
+ exp: claimsAccess.exp || 0,
278
+ iat: claimsAccess.iat || 0,
279
+ sub: claimsAccess.sub || '',
280
+ user: {
281
+ id: claimsId?.sub || '',
282
+ name: claimsId?.name || '',
283
+ email: claimsId?.email || '',
284
+ given_name: claimsId?.given_name,
285
+ family_name: claimsId?.family_name,
286
+ picture: claimsId?.picture
287
+ },
288
+ permissions: claimsAccess.permissions,
289
+ context: {
290
+ ...claimsAccess['https://hemia.mx/context'],
291
+ ...claimsId?.['https://hemia.mx/context']
292
+ }
275
293
  };
276
294
  }
277
295
  catch (e) {
@@ -334,13 +352,19 @@ let AuthService = class AuthService {
334
352
  refreshToken: session.refreshToken,
335
353
  sessionId: session.ssoSessionId
336
354
  });
337
- const { access_token, refresh_token, id_token, expires_in } = response.data;
355
+ if (response.status !== 200) {
356
+ throw new CustomHttpError('Token refresh failed', response.status, 'token_refresh_failed');
357
+ }
358
+ if (!response.data.data) {
359
+ throw new InternalServerError('No token data received from SSO during refresh', 'invalid_token_response');
360
+ }
361
+ const { access_token, refresh_token, id_token, expires_in, session_id } = response.data.data;
338
362
  const updatedSession = {
339
363
  accessToken: access_token,
340
364
  refreshToken: refresh_token || session.refreshToken,
341
365
  idToken: id_token || session.idToken,
342
366
  expiresAt: Date.now() + (expires_in * 1000),
343
- sessionId: response.data.session_id || '',
367
+ sessionId: session_id || '',
344
368
  createdAt: Date.now().toString()
345
369
  };
346
370
  await this.storage.set(`x-session:${sessionId}`, updatedSession, expires_in);
@@ -356,11 +380,13 @@ AuthService = __decorate([
356
380
  const AUTH_SERVICE_ID = Symbol.for('HemiaAuthService');
357
381
 
358
382
  /**
359
- * Controller Abstracto Reutilizable
383
+ * Controller AuthController
360
384
  * Gestiona automáticamente Login, Callback, Me y Logout.
361
385
  */
362
- let AbstractAuthController = class AbstractAuthController {
363
- constructor() { }
386
+ let AuthController = class AuthController {
387
+ constructor(authService) {
388
+ this.authService = authService;
389
+ }
364
390
  async login(req, res) {
365
391
  try {
366
392
  const autoParam = typeof req.query.auto === 'string' ? req.query.auto : 'false';
@@ -477,22 +503,18 @@ let AbstractAuthController = class AbstractAuthController {
477
503
  return res.status(200).json({ success: true });
478
504
  }
479
505
  };
480
- __decorate([
481
- inject(AUTH_SERVICE_ID),
482
- __metadata("design:type", AuthService)
483
- ], AbstractAuthController.prototype, "authService", void 0);
484
506
  __decorate([
485
507
  Get('/login'),
486
508
  __metadata("design:type", Function),
487
509
  __metadata("design:paramtypes", [Object, Object]),
488
510
  __metadata("design:returntype", Promise)
489
- ], AbstractAuthController.prototype, "login", null);
511
+ ], AuthController.prototype, "login", null);
490
512
  __decorate([
491
513
  Get('/callback'),
492
514
  __metadata("design:type", Function),
493
515
  __metadata("design:paramtypes", [Object, Object]),
494
516
  __metadata("design:returntype", Promise)
495
- ], AbstractAuthController.prototype, "callback", null);
517
+ ], AuthController.prototype, "callback", null);
496
518
  __decorate([
497
519
  Get('/me'),
498
520
  __param(0, Req()),
@@ -500,7 +522,7 @@ __decorate([
500
522
  __metadata("design:type", Function),
501
523
  __metadata("design:paramtypes", [Object, Object]),
502
524
  __metadata("design:returntype", Promise)
503
- ], AbstractAuthController.prototype, "me", null);
525
+ ], AuthController.prototype, "me", null);
504
526
  __decorate([
505
527
  Post('/logout'),
506
528
  __param(0, Req()),
@@ -508,11 +530,12 @@ __decorate([
508
530
  __metadata("design:type", Function),
509
531
  __metadata("design:paramtypes", [Object, Object]),
510
532
  __metadata("design:returntype", Promise)
511
- ], AbstractAuthController.prototype, "logout", null);
512
- AbstractAuthController = __decorate([
513
- injectable(),
514
- __metadata("design:paramtypes", [])
515
- ], AbstractAuthController);
533
+ ], AuthController.prototype, "logout", null);
534
+ AuthController = __decorate([
535
+ Controller('/'),
536
+ __param(0, inject(AUTH_SERVICE_ID)),
537
+ __metadata("design:paramtypes", [AuthService])
538
+ ], AuthController);
516
539
 
517
540
  class AuthCacheAdapter {
518
541
  constructor(externalCache) {
@@ -529,14 +552,21 @@ class AuthCacheAdapter {
529
552
  }
530
553
  }
531
554
 
532
- const registerAuthSdk = (bind, config, cacheFactory) => {
533
- bind(AUTH_SERVICE_ID).toDynamicValue(async (context) => {
534
- const rawCache = await Promise.resolve(cacheFactory(context));
535
- const storageAdapter = new AuthCacheAdapter(rawCache);
536
- const network = new HMNetworkServices(config.ssoBaseUrl);
537
- const jwt = new JwtManager();
538
- return new AuthService(config, storageAdapter, network, jwt);
539
- }).inSingletonScope();
555
+ const authPlugin = (config, cacheFactory, options) => {
556
+ return async (container) => {
557
+ container.bind(AUTH_SERVICE_ID).toDynamicValue(async (context) => {
558
+ const rawCache = await Promise.resolve(cacheFactory(context));
559
+ const storageAdapter = new AuthCacheAdapter(rawCache);
560
+ const network = new HMNetworkServices(config.ssoBaseUrl);
561
+ const jwt = new JwtManager();
562
+ return new AuthService(config, storageAdapter, network, jwt);
563
+ }).inSingletonScope();
564
+ Reflect.defineMetadata(METADATA_KEYS.BASE_PATH, options.basePath, AuthController);
565
+ ControllerRegistry.register(AuthController);
566
+ if (!container.isBound(AuthController)) {
567
+ container.bind(AuthController).toSelf().inSingletonScope();
568
+ }
569
+ };
540
570
  };
541
571
 
542
- export { AUTH_SERVICE_ID, AbstractAuthController, AuthService, InvalidTokenFormatError, SessionError, SessionExpiredError, SessionInvalidError, SessionNotFoundError, TokenRefreshFailedError, registerAuthSdk };
572
+ export { AUTH_SERVICE_ID, AuthController, AuthService, InvalidTokenFormatError, SessionError, SessionExpiredError, SessionInvalidError, SessionNotFoundError, TokenRefreshFailedError, authPlugin };
@@ -180,10 +180,10 @@ exports.AuthService = class AuthService {
180
180
  if (response.status !== 200) {
181
181
  throw new common.CustomHttpError('Token exchange failed', response.status, 'token_exchange_failed');
182
182
  }
183
- if (!response.data.access_token) {
183
+ if (!response.data.data?.access_token) {
184
184
  throw new common.InternalServerError('No access token received from SSO', 'invalid_token_response');
185
185
  }
186
- const { access_token, refresh_token, id_token, expires_in, session_id } = response.data;
186
+ const { access_token, refresh_token, id_token, expires_in, session_id } = response.data.data;
187
187
  const sessionId = crypto.randomBytes(16).toString('hex');
188
188
  const sessionData = {
189
189
  accessToken: access_token,
@@ -268,12 +268,30 @@ exports.AuthService = class AuthService {
268
268
  if (!verify) {
269
269
  throw new SessionInvalidError();
270
270
  }
271
- const claims = this.jwtManager.decode(session.accessToken, true);
272
- if (!claims) {
271
+ const claimsAccess = this.jwtManager.decode(session.accessToken, true);
272
+ if (!claimsAccess) {
273
273
  throw new SessionInvalidError();
274
274
  }
275
+ const claimsId = this.jwtManager.decode(session.idToken, true);
275
276
  return {
276
- ...claims
277
+ aud: claimsAccess.aud,
278
+ iss: claimsAccess.iss || '',
279
+ exp: claimsAccess.exp || 0,
280
+ iat: claimsAccess.iat || 0,
281
+ sub: claimsAccess.sub || '',
282
+ user: {
283
+ id: claimsId?.sub || '',
284
+ name: claimsId?.name || '',
285
+ email: claimsId?.email || '',
286
+ given_name: claimsId?.given_name,
287
+ family_name: claimsId?.family_name,
288
+ picture: claimsId?.picture
289
+ },
290
+ permissions: claimsAccess.permissions,
291
+ context: {
292
+ ...claimsAccess['https://hemia.mx/context'],
293
+ ...claimsId?.['https://hemia.mx/context']
294
+ }
277
295
  };
278
296
  }
279
297
  catch (e) {
@@ -336,13 +354,19 @@ exports.AuthService = class AuthService {
336
354
  refreshToken: session.refreshToken,
337
355
  sessionId: session.ssoSessionId
338
356
  });
339
- const { access_token, refresh_token, id_token, expires_in } = response.data;
357
+ if (response.status !== 200) {
358
+ throw new common.CustomHttpError('Token refresh failed', response.status, 'token_refresh_failed');
359
+ }
360
+ if (!response.data.data) {
361
+ throw new common.InternalServerError('No token data received from SSO during refresh', 'invalid_token_response');
362
+ }
363
+ const { access_token, refresh_token, id_token, expires_in, session_id } = response.data.data;
340
364
  const updatedSession = {
341
365
  accessToken: access_token,
342
366
  refreshToken: refresh_token || session.refreshToken,
343
367
  idToken: id_token || session.idToken,
344
368
  expiresAt: Date.now() + (expires_in * 1000),
345
- sessionId: response.data.session_id || '',
369
+ sessionId: session_id || '',
346
370
  createdAt: Date.now().toString()
347
371
  };
348
372
  await this.storage.set(`x-session:${sessionId}`, updatedSession, expires_in);
@@ -358,11 +382,13 @@ exports.AuthService = __decorate([
358
382
  const AUTH_SERVICE_ID = Symbol.for('HemiaAuthService');
359
383
 
360
384
  /**
361
- * Controller Abstracto Reutilizable
385
+ * Controller AuthController
362
386
  * Gestiona automáticamente Login, Callback, Me y Logout.
363
387
  */
364
- exports.AbstractAuthController = class AbstractAuthController {
365
- constructor() { }
388
+ exports.AuthController = class AuthController {
389
+ constructor(authService) {
390
+ this.authService = authService;
391
+ }
366
392
  async login(req, res) {
367
393
  try {
368
394
  const autoParam = typeof req.query.auto === 'string' ? req.query.auto : 'false';
@@ -479,22 +505,18 @@ exports.AbstractAuthController = class AbstractAuthController {
479
505
  return res.status(200).json({ success: true });
480
506
  }
481
507
  };
482
- __decorate([
483
- inversify.inject(AUTH_SERVICE_ID),
484
- __metadata("design:type", exports.AuthService)
485
- ], exports.AbstractAuthController.prototype, "authService", void 0);
486
508
  __decorate([
487
509
  common.Get('/login'),
488
510
  __metadata("design:type", Function),
489
511
  __metadata("design:paramtypes", [Object, Object]),
490
512
  __metadata("design:returntype", Promise)
491
- ], exports.AbstractAuthController.prototype, "login", null);
513
+ ], exports.AuthController.prototype, "login", null);
492
514
  __decorate([
493
515
  common.Get('/callback'),
494
516
  __metadata("design:type", Function),
495
517
  __metadata("design:paramtypes", [Object, Object]),
496
518
  __metadata("design:returntype", Promise)
497
- ], exports.AbstractAuthController.prototype, "callback", null);
519
+ ], exports.AuthController.prototype, "callback", null);
498
520
  __decorate([
499
521
  common.Get('/me'),
500
522
  __param(0, common.Req()),
@@ -502,7 +524,7 @@ __decorate([
502
524
  __metadata("design:type", Function),
503
525
  __metadata("design:paramtypes", [Object, Object]),
504
526
  __metadata("design:returntype", Promise)
505
- ], exports.AbstractAuthController.prototype, "me", null);
527
+ ], exports.AuthController.prototype, "me", null);
506
528
  __decorate([
507
529
  common.Post('/logout'),
508
530
  __param(0, common.Req()),
@@ -510,11 +532,12 @@ __decorate([
510
532
  __metadata("design:type", Function),
511
533
  __metadata("design:paramtypes", [Object, Object]),
512
534
  __metadata("design:returntype", Promise)
513
- ], exports.AbstractAuthController.prototype, "logout", null);
514
- exports.AbstractAuthController = __decorate([
515
- inversify.injectable(),
516
- __metadata("design:paramtypes", [])
517
- ], exports.AbstractAuthController);
535
+ ], exports.AuthController.prototype, "logout", null);
536
+ exports.AuthController = __decorate([
537
+ common.Controller('/'),
538
+ __param(0, inversify.inject(AUTH_SERVICE_ID)),
539
+ __metadata("design:paramtypes", [exports.AuthService])
540
+ ], exports.AuthController);
518
541
 
519
542
  class AuthCacheAdapter {
520
543
  constructor(externalCache) {
@@ -531,14 +554,21 @@ class AuthCacheAdapter {
531
554
  }
532
555
  }
533
556
 
534
- const registerAuthSdk = (bind, config, cacheFactory) => {
535
- bind(AUTH_SERVICE_ID).toDynamicValue(async (context) => {
536
- const rawCache = await Promise.resolve(cacheFactory(context));
537
- const storageAdapter = new AuthCacheAdapter(rawCache);
538
- const network = new networkServices.HMNetworkServices(config.ssoBaseUrl);
539
- const jwt = new jwtManager.JwtManager();
540
- return new exports.AuthService(config, storageAdapter, network, jwt);
541
- }).inSingletonScope();
557
+ const authPlugin = (config, cacheFactory, options) => {
558
+ return async (container) => {
559
+ container.bind(AUTH_SERVICE_ID).toDynamicValue(async (context) => {
560
+ const rawCache = await Promise.resolve(cacheFactory(context));
561
+ const storageAdapter = new AuthCacheAdapter(rawCache);
562
+ const network = new networkServices.HMNetworkServices(config.ssoBaseUrl);
563
+ const jwt = new jwtManager.JwtManager();
564
+ return new exports.AuthService(config, storageAdapter, network, jwt);
565
+ }).inSingletonScope();
566
+ Reflect.defineMetadata(common.METADATA_KEYS.BASE_PATH, options.basePath, exports.AuthController);
567
+ common.ControllerRegistry.register(exports.AuthController);
568
+ if (!container.isBound(exports.AuthController)) {
569
+ container.bind(exports.AuthController).toSelf().inSingletonScope();
570
+ }
571
+ };
542
572
  };
543
573
 
544
574
  exports.AUTH_SERVICE_ID = AUTH_SERVICE_ID;
@@ -548,4 +578,4 @@ exports.SessionExpiredError = SessionExpiredError;
548
578
  exports.SessionInvalidError = SessionInvalidError;
549
579
  exports.SessionNotFoundError = SessionNotFoundError;
550
580
  exports.TokenRefreshFailedError = TokenRefreshFailedError;
551
- exports.registerAuthSdk = registerAuthSdk;
581
+ exports.authPlugin = authPlugin;
@@ -1,12 +1,12 @@
1
1
  import { Request, Response } from "express";
2
2
  import { AuthService } from "../services/auth.service";
3
3
  /**
4
- * Controller Abstracto Reutilizable
4
+ * Controller AuthController
5
5
  * Gestiona automáticamente Login, Callback, Me y Logout.
6
6
  */
7
- export declare abstract class AbstractAuthController {
8
- protected readonly authService: AuthService;
9
- constructor();
7
+ export declare class AuthController {
8
+ private readonly authService;
9
+ constructor(authService: AuthService);
10
10
  login(req: Request, res: Response): Promise<void>;
11
11
  callback(req: Request, res: Response): Promise<void>;
12
12
  me(req: Request, res: Response): Promise<Response>;
@@ -1,4 +1,4 @@
1
- export * from "./controllers/abstract-auth.controller";
1
+ export * from "./controllers/auth.controller";
2
2
  export * from "./services";
3
3
  export * from "./types";
4
4
  export * from "./errors";
@@ -1,5 +1,8 @@
1
- import { Bind, ResolutionContext } from "inversify";
1
+ import { ResolutionContext } from "inversify";
2
2
  import { IAuthConfig } from "./types";
3
3
  import { IHemiaCacheService } from "./adapters";
4
+ import { Plugin } from "@hemia/common";
4
5
  export type CacheFactory = (context: ResolutionContext) => Promise<IHemiaCacheService> | IHemiaCacheService;
5
- export declare const registerAuthSdk: (bind: Bind, config: IAuthConfig, cacheFactory: CacheFactory) => void;
6
+ export declare const authPlugin: (config: IAuthConfig, cacheFactory: CacheFactory, options: {
7
+ basePath: string;
8
+ }) => Plugin;
@@ -1,6 +1,6 @@
1
1
  import { HMNetworkServices } from '@hemia/network-services';
2
2
  import { JwtManager } from '@hemia/jwt-manager';
3
- import { IAuthConfig, ICallbackResponse, ILoginParams, ISessionStorage, ISessionUser, IStoredState } from '../types';
3
+ import { IAuthConfig, ICallbackResponse, ILoginParams, ISessionStorage, ISessionUser, IStoredState, SessionAccess } from '../types';
4
4
  export declare class AuthService {
5
5
  private readonly config;
6
6
  private readonly storage;
@@ -33,7 +33,7 @@ export declare class AuthService {
33
33
  * @param sessionId Identificador de la sesión
34
34
  * @returns Claims del access token o error si el token no es válido
35
35
  */
36
- getSessionAccess(sessionId: string): Promise<any>;
36
+ getSessionAccess(sessionId: string): Promise<SessionAccess>;
37
37
  /**
38
38
  * Cierra la sesión del usuario tanto en el SSO como localmente.
39
39
  * @param sessionId Identificador de la sesión
@@ -9,3 +9,4 @@ export * from "./jwt-manager.interface";
9
9
  export * from "./standard-claims.interface";
10
10
  export * from "./session-data.interface";
11
11
  export * from "./session-storage.interface";
12
+ export * from "./session-access.interface";
@@ -0,0 +1,20 @@
1
+ export interface SessionAccess {
2
+ sub: string;
3
+ exp: number;
4
+ iat: number;
5
+ iss: string;
6
+ permissions?: string[];
7
+ context?: any;
8
+ user?: AccessUser;
9
+ [key: string]: any;
10
+ }
11
+ interface AccessUser {
12
+ id: string;
13
+ name?: string;
14
+ email?: string;
15
+ given_name?: string;
16
+ family_name?: string;
17
+ picture?: string;
18
+ [key: string]: any;
19
+ }
20
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hemia/auth-sdk",
3
- "version": "0.0.8",
3
+ "version": "0.0.10",
4
4
  "description": "Hemia SDK for authentication",
5
5
  "main": "dist/hemia-auth-sdk.js",
6
6
  "module": "dist/hemia-auth-sdk.esm.js",
@@ -15,7 +15,7 @@
15
15
  },
16
16
  "devDependencies": {
17
17
  "@hemia/cache-manager": "^0.0.5",
18
- "@hemia/common": "^0.0.2",
18
+ "@hemia/common": "^0.0.9",
19
19
  "@hemia/jwt-manager": "^0.0.4",
20
20
  "@hemia/network-services": "^0.0.3",
21
21
  "@rollup/plugin-commonjs": "^26.0.1",
@@ -43,7 +43,7 @@
43
43
  ],
44
44
  "peerDependencies": {
45
45
  "@hemia/cache-manager": "^0.0.5",
46
- "@hemia/common": "^0.0.2",
46
+ "@hemia/common": "^0.0.9",
47
47
  "@hemia/jwt-manager": "^0.0.4",
48
48
  "@hemia/network-services": "^0.0.3",
49
49
  "inversify": "^7.11.0",