prime-sdk 3.0.7-beta.0 → 3.0.7

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.
Files changed (123) hide show
  1. package/.eslintrc.js +0 -4
  2. package/.vscode/settings.json +4 -0
  3. package/.yarn/install-state.gz +0 -0
  4. package/README.md +0 -307
  5. package/dist/external/aws/sns/sns.provider.d.ts +1 -0
  6. package/dist/external/aws/sns/sns.provider.js +8 -2
  7. package/dist/external/aws/sns/sns.provider.js.map +1 -1
  8. package/dist/external/aws/sns/sns.service.d.ts +4 -1
  9. package/dist/external/aws/sns/sns.service.js +21 -2
  10. package/dist/external/aws/sns/sns.service.js.map +1 -1
  11. package/dist/external/redis/interfaces/redis.interface.d.ts +1 -0
  12. package/dist/external/redis/interfaces/redis.interface.js.map +1 -1
  13. package/dist/external/redis/redis.service.d.ts +1 -0
  14. package/dist/external/redis/redis.service.js +13 -0
  15. package/dist/external/redis/redis.service.js.map +1 -1
  16. package/dist/index.d.ts +2 -15
  17. package/dist/index.js +1 -25
  18. package/dist/index.js.map +1 -1
  19. package/dist/lib/cache/cache.d.ts +1 -0
  20. package/dist/lib/cache/cache.js +3 -0
  21. package/dist/lib/cache/cache.js.map +1 -1
  22. package/dist/lib/cache/interfaces/cache.interface.d.ts +1 -0
  23. package/dist/lib/cache/interfaces/cache.interface.js.map +1 -1
  24. package/dist/lib/events/types/event.type.d.ts +2 -0
  25. package/dist/tsconfig.build.tsbuildinfo +1 -1
  26. package/package.json +1 -4
  27. package/src/external/aws/sns/sns.provider.ts +9 -2
  28. package/src/external/aws/sns/sns.service.ts +26 -2
  29. package/src/external/redis/interfaces/redis.interface.ts +6 -0
  30. package/src/external/redis/redis.service.ts +17 -0
  31. package/src/index.ts +3 -42
  32. package/src/lib/cache/cache.ts +8 -0
  33. package/src/lib/cache/interfaces/cache.interface.ts +6 -0
  34. package/src/lib/events/types/event.type.ts +3 -0
  35. package/tsconfig.json +0 -1
  36. package/dist/lib/entraID/customError/entraID.exception.d.ts +0 -5
  37. package/dist/lib/entraID/customError/entraID.exception.js +0 -43
  38. package/dist/lib/entraID/customError/entraID.exception.js.map +0 -1
  39. package/dist/lib/entraID/decorators/current-user.decorator.d.ts +0 -1
  40. package/dist/lib/entraID/decorators/current-user.decorator.js +0 -9
  41. package/dist/lib/entraID/decorators/current-user.decorator.js.map +0 -1
  42. package/dist/lib/entraID/decorators/public.decorator.d.ts +0 -2
  43. package/dist/lib/entraID/decorators/public.decorator.js +0 -8
  44. package/dist/lib/entraID/decorators/public.decorator.js.map +0 -1
  45. package/dist/lib/entraID/decorators/roles.decorator.d.ts +0 -2
  46. package/dist/lib/entraID/decorators/roles.decorator.js +0 -8
  47. package/dist/lib/entraID/decorators/roles.decorator.js.map +0 -1
  48. package/dist/lib/entraID/entraID.constants.d.ts +0 -2
  49. package/dist/lib/entraID/entraID.constants.js +0 -6
  50. package/dist/lib/entraID/entraID.constants.js.map +0 -1
  51. package/dist/lib/entraID/entraID.module.d.ts +0 -14
  52. package/dist/lib/entraID/entraID.module.js +0 -56
  53. package/dist/lib/entraID/entraID.module.js.map +0 -1
  54. package/dist/lib/entraID/entraID.service.d.ts +0 -25
  55. package/dist/lib/entraID/entraID.service.js +0 -166
  56. package/dist/lib/entraID/entraID.service.js.map +0 -1
  57. package/dist/lib/entraID/guards/entra-auth.guard.d.ts +0 -21
  58. package/dist/lib/entraID/guards/entra-auth.guard.js +0 -70
  59. package/dist/lib/entraID/guards/entra-auth.guard.js.map +0 -1
  60. package/dist/lib/entraID/guards/roles.guard.d.ts +0 -7
  61. package/dist/lib/entraID/guards/roles.guard.js +0 -41
  62. package/dist/lib/entraID/guards/roles.guard.js.map +0 -1
  63. package/dist/lib/entraID/interfaces/entraID-service.interface.d.ts +0 -7
  64. package/dist/lib/entraID/interfaces/entraID-service.interface.js +0 -3
  65. package/dist/lib/entraID/interfaces/entraID-service.interface.js.map +0 -1
  66. package/dist/lib/entraID/internal-token/internal-token.module.d.ts +0 -2
  67. package/dist/lib/entraID/internal-token/internal-token.module.js +0 -21
  68. package/dist/lib/entraID/internal-token/internal-token.module.js.map +0 -1
  69. package/dist/lib/entraID/internal-token/internal-token.service.d.ts +0 -10
  70. package/dist/lib/entraID/internal-token/internal-token.service.js +0 -76
  71. package/dist/lib/entraID/internal-token/internal-token.service.js.map +0 -1
  72. package/dist/lib/entraID/microsoft/microsoft.module.d.ts +0 -2
  73. package/dist/lib/entraID/microsoft/microsoft.module.js +0 -21
  74. package/dist/lib/entraID/microsoft/microsoft.module.js.map +0 -1
  75. package/dist/lib/entraID/microsoft/microsoft.service.d.ts +0 -14
  76. package/dist/lib/entraID/microsoft/microsoft.service.js +0 -132
  77. package/dist/lib/entraID/microsoft/microsoft.service.js.map +0 -1
  78. package/dist/lib/entraID/security/security.module.d.ts +0 -2
  79. package/dist/lib/entraID/security/security.module.js +0 -21
  80. package/dist/lib/entraID/security/security.module.js.map +0 -1
  81. package/dist/lib/entraID/security/security.service.d.ts +0 -9
  82. package/dist/lib/entraID/security/security.service.js +0 -65
  83. package/dist/lib/entraID/security/security.service.js.map +0 -1
  84. package/dist/lib/entraID/types/entraID-module-init.types.d.ts +0 -18
  85. package/dist/lib/entraID/types/entraID-module-init.types.js +0 -3
  86. package/dist/lib/entraID/types/entraID-module-init.types.js.map +0 -1
  87. package/dist/lib/entraID/types/entraID.type.d.ts +0 -52
  88. package/dist/lib/entraID/types/entraID.type.js +0 -3
  89. package/dist/lib/entraID/types/entraID.type.js.map +0 -1
  90. package/dist/lib/entraID/utils/cookie.utils.d.ts +0 -7
  91. package/dist/lib/entraID/utils/cookie.utils.js +0 -42
  92. package/dist/lib/entraID/utils/cookie.utils.js.map +0 -1
  93. package/dist/lib/entraID/utils/crypto.utils.d.ts +0 -9
  94. package/dist/lib/entraID/utils/crypto.utils.js +0 -47
  95. package/dist/lib/entraID/utils/crypto.utils.js.map +0 -1
  96. package/dist/lib/entraID/utils/index.d.ts +0 -2
  97. package/dist/lib/entraID/utils/index.js +0 -8
  98. package/dist/lib/entraID/utils/index.js.map +0 -1
  99. package/dist/lib/entraID/utils/token.utils.d.ts +0 -6
  100. package/dist/lib/entraID/utils/token.utils.js +0 -24
  101. package/dist/lib/entraID/utils/token.utils.js.map +0 -1
  102. package/src/lib/entraID/customError/entraID.exception.ts +0 -43
  103. package/src/lib/entraID/decorators/current-user.decorator.ts +0 -8
  104. package/src/lib/entraID/decorators/public.decorator.ts +0 -5
  105. package/src/lib/entraID/decorators/roles.decorator.ts +0 -5
  106. package/src/lib/entraID/entraID.constants.ts +0 -2
  107. package/src/lib/entraID/entraID.module.ts +0 -78
  108. package/src/lib/entraID/entraID.service.ts +0 -206
  109. package/src/lib/entraID/guards/entra-auth.guard.ts +0 -77
  110. package/src/lib/entraID/guards/roles.guard.ts +0 -34
  111. package/src/lib/entraID/interfaces/entraID-service.interface.ts +0 -12
  112. package/src/lib/entraID/internal-token/internal-token.module.ts +0 -8
  113. package/src/lib/entraID/internal-token/internal-token.service.ts +0 -66
  114. package/src/lib/entraID/microsoft/microsoft.module.ts +0 -8
  115. package/src/lib/entraID/microsoft/microsoft.service.ts +0 -158
  116. package/src/lib/entraID/security/security.module.ts +0 -8
  117. package/src/lib/entraID/security/security.service.ts +0 -68
  118. package/src/lib/entraID/types/entraID-module-init.types.ts +0 -25
  119. package/src/lib/entraID/types/entraID.type.ts +0 -57
  120. package/src/lib/entraID/utils/cookie.utils.ts +0 -50
  121. package/src/lib/entraID/utils/crypto.utils.ts +0 -53
  122. package/src/lib/entraID/utils/index.ts +0 -2
  123. package/src/lib/entraID/utils/token.utils.ts +0 -20
@@ -1,34 +0,0 @@
1
- import {
2
- CanActivate,
3
- ExecutionContext,
4
- ForbiddenException,
5
- Injectable,
6
- } from '@nestjs/common';
7
- import { Reflector } from '@nestjs/core';
8
- import { ROLES_KEY } from '../decorators/roles.decorator';
9
-
10
- @Injectable()
11
- export class RolesGuard implements CanActivate {
12
- constructor(private readonly reflector: Reflector) {}
13
-
14
- canActivate(context: ExecutionContext): boolean {
15
- const required = this.reflector.getAllAndOverride<string[]>(ROLES_KEY, [
16
- context.getHandler(),
17
- context.getClass(),
18
- ]);
19
-
20
- if (!required?.length) return true;
21
-
22
- const { user } = context.switchToHttp().getRequest();
23
- const userGroups: string[] = (user?.groups ?? []).map(
24
- (g: { displayName: string }) => g.displayName,
25
- );
26
-
27
- const allowed = required.some((role) => userGroups.includes(role));
28
- if (!allowed) {
29
- throw new ForbiddenException('INVALID_GROUP');
30
- }
31
-
32
- return true;
33
- }
34
- }
@@ -1,12 +0,0 @@
1
- import {
2
- AuthResult,
3
- CallbackParams,
4
- UrlRedirectSso,
5
- } from '../types/entraID.type';
6
-
7
- export interface IEntraIDService {
8
- handleCallback(params: CallbackParams): Promise<AuthResult>;
9
- initiateLogin(): Promise<UrlRedirectSso>;
10
- refresh(refreshToken: string): Promise<AuthResult>;
11
- logout(userId: string): Promise<void>;
12
- }
@@ -1,8 +0,0 @@
1
- import { Module } from '@nestjs/common';
2
- import { InternalTokenService } from './internal-token.service';
3
-
4
- @Module({
5
- providers: [InternalTokenService],
6
- exports: [InternalTokenService],
7
- })
8
- export class InternalTokenModule {}
@@ -1,66 +0,0 @@
1
- import { Inject, Injectable } from '@nestjs/common';
2
- import { randomUUID } from 'crypto';
3
- import jwt from 'jsonwebtoken';
4
- import { ENTRA_ID_CONFIG } from '../entraID.constants';
5
- import { EntraIDException } from '../customError/entraID.exception';
6
- import { EntraIDSetup } from '../types/entraID-module-init.types';
7
- import { EntraUser, TokenEnrichmentContext } from '../types/entraID.type';
8
-
9
- @Injectable()
10
- export class InternalTokenService {
11
- constructor(@Inject(ENTRA_ID_CONFIG) private readonly config: EntraIDSetup) {}
12
-
13
- async sign(context: TokenEnrichmentContext): Promise<string> {
14
- const customClaims = await this.enrichTokenPayload(context);
15
-
16
- this.assertNoReservedClaimCollision(customClaims);
17
-
18
- return jwt.sign(
19
- { jti: randomUUID(), ...context.user, ...customClaims },
20
- this.config.jwtSecret,
21
- {
22
- algorithm: 'HS256',
23
- expiresIn: (this.config.jwtExpiresIn ??
24
- '8h') as jwt.SignOptions['expiresIn'],
25
- },
26
- );
27
- }
28
-
29
- protected async enrichTokenPayload(
30
- _context: TokenEnrichmentContext,
31
- ): Promise<Record<string, unknown>> {
32
- return {};
33
- }
34
-
35
- verify(token: string): EntraUser {
36
- try {
37
- return jwt.verify(token, this.config.jwtSecret, {
38
- algorithms: ['HS256'],
39
- }) as unknown as EntraUser;
40
- } catch (err) {
41
- if (err instanceof jwt.TokenExpiredError) {
42
- throw new EntraIDException('TOKEN_EXPIRED');
43
- }
44
- throw new EntraIDException('TOKEN_INVALID');
45
- }
46
- }
47
-
48
- private assertNoReservedClaimCollision(
49
- customClaims: Record<string, unknown>,
50
- ) {
51
- const reserved = [
52
- 'sub',
53
- 'iss',
54
- 'aud',
55
- 'exp',
56
- 'iat',
57
- 'nbf',
58
- 'jti',
59
- 'groups',
60
- ];
61
- const collision = reserved.find((claim) => claim in customClaims);
62
- if (collision) {
63
- throw new EntraIDException('RESERVED_CLAIM_OVERRIDE');
64
- }
65
- }
66
- }
@@ -1,8 +0,0 @@
1
- import { Module } from '@nestjs/common';
2
- import { MicrosoftService } from './microsoft.service';
3
-
4
- @Module({
5
- providers: [MicrosoftService],
6
- exports: [MicrosoftService],
7
- })
8
- export class MicrosoftModule {}
@@ -1,158 +0,0 @@
1
- import { Inject, Injectable } from '@nestjs/common';
2
- import { EntraIDException } from '../customError/entraID.exception';
3
- import { AzureTokenResponse, GraphUser } from '../types/entraID.type';
4
- import { EntraIDSetup } from '../types/entraID-module-init.types';
5
- import { ENTRA_ID_CONFIG, MICROSOFT_AUTHORITY_URL } from '../entraID.constants';
6
-
7
- const GRAPH_BASE = 'https://graph.microsoft.com/v1.0';
8
- const FETCH_TIMEOUT_MS = 15_000;
9
-
10
- @Injectable()
11
- export class MicrosoftService {
12
- constructor(@Inject(ENTRA_ID_CONFIG) private readonly config: EntraIDSetup) {}
13
-
14
- async exchangeCode(code: string): Promise<AzureTokenResponse> {
15
- const body = new URLSearchParams({
16
- client_id: this.config.clientID,
17
- client_secret: this.config.clientSecret,
18
- code,
19
- redirect_uri: this.config.redirectUri,
20
- grant_type: 'authorization_code',
21
- scope:
22
- this.config.scope ??
23
- 'openid profile email User.Read GroupMember.Read.All',
24
- });
25
-
26
- const authorityUrl = this.config.authorityUrl ?? MICROSOFT_AUTHORITY_URL;
27
-
28
- const response = await fetch(
29
- `${authorityUrl}/${this.config.tenantID}/oauth2/v2.0/token`,
30
- {
31
- method: 'POST',
32
- headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
33
- body: body.toString(),
34
- signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),
35
- },
36
- );
37
-
38
- if (!response.ok) throw new EntraIDException('CODE_EXCHANGE_FAILED');
39
-
40
- const tokens = (await response.json()) as AzureTokenResponse;
41
-
42
- if (!tokens.access_token || !tokens.id_token) {
43
- throw new EntraIDException('CODE_EXCHANGE_FAILED');
44
- }
45
-
46
- return tokens;
47
- }
48
-
49
- async refreshToken(refreshToken: string): Promise<AzureTokenResponse> {
50
- const body = new URLSearchParams({
51
- client_id: this.config.clientID,
52
- client_secret: this.config.clientSecret,
53
- refresh_token: refreshToken,
54
- grant_type: 'refresh_token',
55
- });
56
-
57
- const authorityUrl = this.config.authorityUrl ?? MICROSOFT_AUTHORITY_URL;
58
-
59
- const response = await fetch(
60
- `${authorityUrl}/${this.config.tenantID}/oauth2/v2.0/token`,
61
- {
62
- method: 'POST',
63
- headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
64
- body: body.toString(),
65
- signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),
66
- },
67
- );
68
-
69
- if (!response.ok) throw new EntraIDException('REFRESH_TOKEN_FAILED');
70
-
71
- const tokens = (await response.json()) as AzureTokenResponse;
72
-
73
- if (!tokens.access_token)
74
- throw new EntraIDException('REFRESH_TOKEN_FAILED');
75
-
76
- return tokens;
77
- }
78
-
79
- // Requer Application permission "User.RevokeSessions.All"
80
- async revokeUserSessions(userId: string): Promise<void> {
81
- const adminToken = await this.getClientCredentialsToken();
82
-
83
- const response = await fetch(
84
- `${GRAPH_BASE}/users/${userId}/revokeSignInSessions`,
85
- {
86
- method: 'POST',
87
- headers: { Authorization: `Bearer ${adminToken}` },
88
- signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),
89
- },
90
- );
91
-
92
- if (!response.ok) throw new EntraIDException('REVOKE_SESSIONS_FAILED');
93
- }
94
-
95
- private async getClientCredentialsToken(): Promise<string> {
96
- const authorityUrl = this.config.authorityUrl ?? MICROSOFT_AUTHORITY_URL;
97
-
98
- const body = new URLSearchParams({
99
- client_id: this.config.clientID,
100
- client_secret: this.config.clientSecret,
101
- scope: 'https://graph.microsoft.com/.default',
102
- grant_type: 'client_credentials',
103
- });
104
-
105
- const response = await fetch(
106
- `${authorityUrl}/${this.config.tenantID}/oauth2/v2.0/token`,
107
- {
108
- method: 'POST',
109
- headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
110
- body: body.toString(),
111
- signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),
112
- },
113
- );
114
-
115
- if (!response.ok) throw new EntraIDException('REVOKE_SESSIONS_FAILED');
116
-
117
- const data = (await response.json()) as { access_token: string };
118
- return data.access_token;
119
- }
120
-
121
- async getMe(accessToken: string): Promise<GraphUser> {
122
- const response = await fetch(
123
- `${GRAPH_BASE}/me?$select=id,displayName,mail,userPrincipalName,employeeId`,
124
- {
125
- headers: { Authorization: `Bearer ${accessToken}` },
126
- signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),
127
- },
128
- );
129
-
130
- if (!response.ok) throw new EntraIDException('GRAPH_FETCH_FAILED');
131
-
132
- return (await response.json()) as GraphUser;
133
- }
134
-
135
- async getMemberOf(accessToken: string): Promise<{ displayName: string }[]> {
136
- const allGroups: { displayName: string }[] = [];
137
- let url: string | null =
138
- `${GRAPH_BASE}/me/memberOf?$select=displayName&$top=100`;
139
-
140
- while (url) {
141
- const response = await fetch(url, {
142
- headers: { Authorization: `Bearer ${accessToken}` },
143
- signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),
144
- });
145
- if (!response.ok) throw new EntraIDException('GRAPH_FETCH_FAILED');
146
-
147
- const data = (await response.json()) as {
148
- value: { displayName: string }[];
149
- '@odata.nextLink'?: string;
150
- };
151
-
152
- allGroups.push(...data.value);
153
- url = data['@odata.nextLink'] ?? null;
154
- }
155
-
156
- return allGroups;
157
- }
158
- }
@@ -1,8 +0,0 @@
1
- import { Module } from '@nestjs/common';
2
- import { SecurityService } from './security.service';
3
-
4
- @Module({
5
- providers: [SecurityService],
6
- exports: [SecurityService],
7
- })
8
- export class SecurityModule {}
@@ -1,68 +0,0 @@
1
- import { Injectable } from '@nestjs/common';
2
- import { EntraIDException } from '../customError/entraID.exception';
3
-
4
- const PATH_TRAVERSAL_PATTERNS = [
5
- /\.\.[/\\]/,
6
- /\.\.[/\\].*\.\.[/\\]/,
7
- /%2e%2e[/\\]/i,
8
- /%2e%2e%2f/i,
9
- /%2e%2e%5c/i,
10
- ];
11
-
12
- const NULL_BYTE_PATTERN = /\0|%00/;
13
-
14
- const DANGEROUS_CHARS = /<|>|"|'|`|\$\{|javascript:/i;
15
-
16
- @Injectable()
17
- export class SecurityService {
18
- validateInput(value: string, field = 'input'): string {
19
- if (NULL_BYTE_PATTERN.test(value)) {
20
- throw new EntraIDException('SECURITY_NULL_BYTE');
21
- }
22
-
23
- if (PATH_TRAVERSAL_PATTERNS.some((p) => p.test(value))) {
24
- throw new EntraIDException('SECURITY_PATH_TRAVERSAL');
25
- }
26
-
27
- if (DANGEROUS_CHARS.test(value)) {
28
- throw new EntraIDException('SECURITY_INVALID_CHARS');
29
- }
30
-
31
- void field;
32
- return value.trim();
33
- }
34
-
35
- validateRedirectUri(uri: string, allowedUri: string): void {
36
- try {
37
- const parsed = new URL(uri);
38
- const allowed = new URL(allowedUri);
39
-
40
- if (
41
- parsed.hostname !== allowed.hostname ||
42
- parsed.protocol !== allowed.protocol
43
- ) {
44
- throw new EntraIDException('SECURITY_OPEN_REDIRECT');
45
- }
46
- } catch (err) {
47
- if (err instanceof EntraIDException) throw err;
48
- throw new EntraIDException('SECURITY_INVALID_URL');
49
- }
50
- }
51
-
52
- validateCallbackParams(params: {
53
- code?: string;
54
- state?: string;
55
- error?: string;
56
- }): void {
57
- if (params.error) {
58
- throw new EntraIDException('OAUTH_PROVIDER_ERROR');
59
- }
60
-
61
- if (!params.code || !params.state) {
62
- throw new EntraIDException('OAUTH_MISSING_PARAMS');
63
- }
64
-
65
- this.validateInput(params.code, 'code');
66
- this.validateInput(params.state, 'state');
67
- }
68
- }
@@ -1,25 +0,0 @@
1
- import {
2
- InjectionToken,
3
- ModuleMetadata,
4
- OptionalFactoryDependency,
5
- } from '@nestjs/common';
6
-
7
- export type EntraIDSetup = {
8
- tenantID: string;
9
- clientID: string;
10
- clientSecret: string;
11
- stateSecret: string;
12
- scope?: string;
13
- prompt?: string;
14
- authorityUrl?: string;
15
- redirectUri: string;
16
-
17
- jwtSecret: string;
18
- jwtExpiresIn?: string | number;
19
- };
20
-
21
- export type EntraIDAsyncOptions = {
22
- imports?: ModuleMetadata['imports'];
23
- inject?: Array<InjectionToken | OptionalFactoryDependency>;
24
- useFactory: (...args: any[]) => EntraIDSetup | Promise<EntraIDSetup>;
25
- };
@@ -1,57 +0,0 @@
1
- export type CreateStateNonce = { nonce: string; state: string };
2
-
3
- export type UrlRedirectSso = string;
4
-
5
- export type CallbackParams = {
6
- code?: string;
7
- state?: string;
8
- error?: string;
9
- error_description?: string;
10
- };
11
-
12
- export type AzureTokenResponse = {
13
- access_token: string;
14
- id_token: string;
15
- refresh_token?: string;
16
- token_type: string;
17
- expires_in: number;
18
- };
19
-
20
- export type IdTokenPayload = {
21
- sub: string;
22
- name: string;
23
- preferred_username?: string;
24
- email?: string;
25
- upn?: string;
26
- nonce: string;
27
- aud: string;
28
- iss: string;
29
- exp: number;
30
- };
31
-
32
- export type TokenEnrichmentContext = {
33
- user: EntraUser;
34
- accessToken: string;
35
- };
36
-
37
- export type GraphUser = {
38
- id: string;
39
- displayName: string;
40
- mail: string | null;
41
- userPrincipalName: string;
42
- employeeId?: string | null;
43
- };
44
-
45
- export type EntraUser = {
46
- entraId: string;
47
- email: string;
48
- name: string;
49
- tenantId: string;
50
- matricula?: string | null;
51
- } & Record<string, unknown>;
52
-
53
- export type AuthResult = {
54
- token: string;
55
- user: EntraUser;
56
- refreshToken?: string;
57
- };
@@ -1,50 +0,0 @@
1
- import { Response } from 'express';
2
- import { EntraUser } from '../types/entraID.type';
3
-
4
- const IS_PRODUCTION = process.env.NODE_ENV === 'production';
5
-
6
- const BASE_COOKIE_OPTIONS = {
7
- httpOnly: true,
8
- secure: IS_PRODUCTION,
9
- sameSite: (IS_PRODUCTION ? 'none' : 'lax') as 'none' | 'lax',
10
- path: '/',
11
- };
12
-
13
- const REFRESH_TOKEN_MAX_AGE = 30 * 24 * 60 * 60 * 1000; // 30 dias
14
-
15
- export class CookieUtils {
16
- static setAuthCookie(
17
- res: Response,
18
- token: string,
19
- refreshToken?: string,
20
- ): void {
21
- res.cookie('auth_token', token, {
22
- ...BASE_COOKIE_OPTIONS,
23
- maxAge: 24 * 60 * 60 * 1000,
24
- });
25
-
26
- if (refreshToken) {
27
- res.cookie('refresh_token', refreshToken, {
28
- ...BASE_COOKIE_OPTIONS,
29
- maxAge: REFRESH_TOKEN_MAX_AGE,
30
- });
31
- }
32
- }
33
-
34
- static setUserDataCookie(res: Response, user: EntraUser): void {
35
- res.cookie('user_data', JSON.stringify(user), {
36
- ...BASE_COOKIE_OPTIONS,
37
- maxAge: 60 * 1000,
38
- });
39
- }
40
-
41
- static clearAuthCookies(res: Response): void {
42
- const clearOptions = {
43
- ...BASE_COOKIE_OPTIONS,
44
- maxAge: 0,
45
- };
46
- res.clearCookie('auth_token', clearOptions);
47
- res.clearCookie('user_data', clearOptions);
48
- res.clearCookie('refresh_token', clearOptions);
49
- }
50
- }
@@ -1,53 +0,0 @@
1
- import crypto from 'crypto';
2
- import { EntraIDException } from '../customError/entraID.exception';
3
- import jwksClient from 'jwks-rsa';
4
-
5
- export class CryptoUtils {
6
- static createSignedPayloadWithHMAC(payload: string, secret: string): string {
7
- const hash = crypto
8
- .createHmac('sha256', secret)
9
- .update(payload)
10
- .digest('base64url');
11
-
12
- return `${payload}.${hash}`;
13
- }
14
-
15
- static generateHash(length: number = 32): string {
16
- return crypto.randomBytes(length).toString('hex');
17
- }
18
-
19
- static verifyPayloadWithHMAC(parts: string[], secret: string) {
20
- if (parts.length !== 2) {
21
- throw new EntraIDException('STATE_MISMATCH');
22
- }
23
-
24
- const [payload, receivedSig] = parts;
25
-
26
- const expectedSig = crypto
27
- .createHmac('sha256', secret)
28
- .update(payload)
29
- .digest('base64url');
30
-
31
- const sigBuf = new Uint8Array(Buffer.from(receivedSig));
32
- const expectedBuf = new Uint8Array(Buffer.from(expectedSig));
33
-
34
- if (
35
- sigBuf.length !== expectedBuf.length ||
36
- !crypto.timingSafeEqual(sigBuf, expectedBuf)
37
- ) {
38
- throw new EntraIDException('STATE_MISMATCH');
39
- }
40
- }
41
-
42
- static async getPublicKeyRsa(
43
- kid: string,
44
- jwksClientInstance: ReturnType<typeof jwksClient>,
45
- ): Promise<crypto.KeyObject> {
46
- try {
47
- const key = await jwksClientInstance.getSigningKey(kid);
48
- return crypto.createPublicKey(key.getPublicKey());
49
- } catch {
50
- throw new EntraIDException('JWKS_KEY_NOT_FOUND');
51
- }
52
- }
53
- }
@@ -1,2 +0,0 @@
1
- export { CookieUtils } from './cookie.utils';
2
- export { TokenUtils } from './token.utils';
@@ -1,20 +0,0 @@
1
- import { Request } from 'express';
2
- import { EntraUser } from '../types/entraID.type';
3
-
4
- export class TokenUtils {
5
- static extractFromRequest(req: Request): string | undefined {
6
- const auth = req.headers.authorization;
7
- if (auth?.startsWith('Bearer ')) return auth.slice(7);
8
- return req.cookies?.auth_token as string | undefined;
9
- }
10
-
11
- static extractUserDataFromCookie(req: Request): EntraUser | null {
12
- const raw = req.cookies?.user_data as string | undefined;
13
- if (!raw) return null;
14
- try {
15
- return JSON.parse(raw) as EntraUser;
16
- } catch {
17
- return null;
18
- }
19
- }
20
- }