@axinom/mosaic-id-guard 0.16.3-rc.8 → 0.17.0-rc.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.
Files changed (48) hide show
  1. package/package.json +7 -6
  2. package/src/common/deprecated/error-code.ts +23 -0
  3. package/src/common/deprecated/index.ts +1 -0
  4. package/src/common/get-authenticated-subject.spec.ts +261 -0
  5. package/src/common/get-authenticated-subject.ts +222 -0
  6. package/src/common/guard-utils.spec.ts +185 -0
  7. package/src/common/guard-utils.ts +207 -0
  8. package/src/common/handle-end-user-authorization.ts +79 -0
  9. package/src/common/handle-management-user-authorization.ts +91 -0
  10. package/src/common/helpers/index.ts +2 -0
  11. package/src/common/helpers/object-helpers.spec.ts +101 -0
  12. package/src/common/helpers/object-helpers.ts +9 -0
  13. package/src/common/helpers/parse-jwt-token-error-handler.ts +143 -0
  14. package/src/common/id-guard-error.ts +12 -0
  15. package/src/common/id-guard-errors.ts +82 -0
  16. package/src/common/index.ts +11 -0
  17. package/src/common/jwt-verify-options.ts +19 -0
  18. package/src/common/parse-jwt-token.spec.ts +784 -0
  19. package/src/common/parse-jwt-token.ts +137 -0
  20. package/src/common/subject-type.ts +10 -0
  21. package/src/common/type-assertions.spec.ts +251 -0
  22. package/src/common/type-assertions.ts +142 -0
  23. package/src/common/types/authenticated-subject-models.ts +117 -0
  24. package/src/common/types/authentication-config.ts +15 -0
  25. package/src/common/types/authentication-request-context.ts +42 -0
  26. package/src/common/types/index.ts +13 -0
  27. package/src/graphql/enforce-strict-permissions.plugin.spec.ts +142 -0
  28. package/src/graphql/enforce-strict-permissions.plugin.ts +163 -0
  29. package/src/graphql/guard-context.spec.ts +86 -0
  30. package/src/graphql/guard-context.ts +89 -0
  31. package/src/graphql/guard-middleware.spec.ts +118 -0
  32. package/src/graphql/guard-middleware.ts +209 -0
  33. package/src/graphql/guard-plugin.spec.ts +990 -0
  34. package/src/graphql/guard-plugin.ts +102 -0
  35. package/src/graphql/index.ts +12 -0
  36. package/src/graphql/subscription-authorization-hook-factory.spec.ts +749 -0
  37. package/src/graphql/subscription-authorization-hook-factory.ts +286 -0
  38. package/src/index.ts +9 -0
  39. package/src/message-bus/guard-message-handler.ts +99 -0
  40. package/src/message-bus/index.ts +3 -0
  41. package/src/message-bus/message-handler-authentication.spec.ts +123 -0
  42. package/src/message-bus/message-handler-authentication.ts +84 -0
  43. package/src/message-bus/message-handler-managed-authentication.spec.ts +111 -0
  44. package/src/message-bus/message-handler-permissions.spec.ts +108 -0
  45. package/src/message-bus/message-handler-permissions.ts +51 -0
  46. package/src/tests/test-utils/index.ts +2 -0
  47. package/src/tests/test-utils/test-message.ts +46 -0
  48. package/src/tests/test-utils/test-user.ts +84 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axinom/mosaic-id-guard",
3
- "version": "0.16.3-rc.8",
3
+ "version": "0.17.0-rc.0",
4
4
  "description": "Authentication and authorization helpers for Axinom Mosaic services",
5
5
  "author": "Axinom",
6
6
  "license": "PROPRIETARY",
@@ -10,7 +10,8 @@
10
10
  "axinom mosaic"
11
11
  ],
12
12
  "files": [
13
- "dist"
13
+ "dist",
14
+ "src"
14
15
  ],
15
16
  "main": "dist/index.js",
16
17
  "types": "dist/index.d.ts",
@@ -27,9 +28,9 @@
27
28
  "lint": "eslint . --ext .ts,.tsx,.js --color --cache"
28
29
  },
29
30
  "dependencies": {
30
- "@axinom/mosaic-id-utils": "^0.10.3-rc.8",
31
- "@axinom/mosaic-message-bus": "^0.11.3-rc.8",
32
- "@axinom/mosaic-service-common": "^0.27.0-rc.6",
31
+ "@axinom/mosaic-id-utils": "^0.11.0-rc.0",
32
+ "@axinom/mosaic-message-bus": "^0.12.0-rc.0",
33
+ "@axinom/mosaic-service-common": "^0.27.0-rc.11",
33
34
  "amqplib": "^0.6.0",
34
35
  "express": "^4.17.1",
35
36
  "express-bearer-token": "^2.4.0",
@@ -60,5 +61,5 @@
60
61
  "publishConfig": {
61
62
  "access": "public"
62
63
  },
63
- "gitHead": "39b4147fb00b4c9500e37effef1ac7b8fb43797f"
64
+ "gitHead": "140f827280ea9616400d5f6d2f770a0911ebf0e2"
64
65
  }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * @deprecated Please use `IdGuardErrors` instead, e.g.
3
+ * ```ts
4
+ * import { IdGuardErrors } from '@axinom/mosaic-id-guard';
5
+ *
6
+ * console.log(IdGuardErrors.AccessTokenRequired.code);
7
+ * ```
8
+ *
9
+ * This is only guaranteed to stay until the end of October 2022.
10
+ */
11
+ export enum ErrorCode {
12
+ AccessTokenInvalid = 'ACCESS_TOKEN_INVALID',
13
+ UserNotAuthorized = 'USER_NOT_AUTHORIZED',
14
+ MalformedToken = 'MALFORMED_TOKEN',
15
+ AccessTokenExpired = 'ACCESS_TOKEN_EXPIRED',
16
+ SigningKeyNotFound = 'SIGNING_KEY_NOT_FOUND',
17
+ JwksError = 'JWKS_ERROR',
18
+ AccessTokenVerificationFailed = 'ACCESS_TOKEN_VERIFICATION_FAILED',
19
+ AuthConfigInvalid = 'AUTH_CONFIG_INVALID',
20
+ AccessTokenRequired = 'ACCESS_TOKEN_REQUIRED',
21
+ IdentityServiceNotAccessible = 'IDENTITY_SERVICE_NOT_ACCESSIBLE',
22
+ UserServiceNotAccessible = 'USER_SERVICE_NOT_ACCESSIBLE',
23
+ }
@@ -0,0 +1 @@
1
+ export * from './error-code';
@@ -0,0 +1,261 @@
1
+ import { TokenExpiredError } from 'jsonwebtoken';
2
+ import createJWKSMock from 'mock-jwks';
3
+ import {
4
+ createTestEndUserApplication,
5
+ createTestUser,
6
+ } from '../tests/test-utils';
7
+ import {
8
+ EMBEDDED_END_USER_TOKEN_KEY,
9
+ getAuthenticatedEndUser,
10
+ getAuthenticatedManagementSubject,
11
+ } from './get-authenticated-subject';
12
+ import { TOKEN_ISSUER_USER_SERVICE } from './jwt-verify-options';
13
+ import { SubjectType } from './subject-type';
14
+ import { AuthenticationConfig } from './types';
15
+
16
+ const authEndpoint = 'https://AUTH_ENDPOINT_URL';
17
+
18
+ describe('getAuthenticatedManagementSubject method --> managed service accounts', () => {
19
+ const jwks = createJWKSMock(authEndpoint);
20
+
21
+ beforeEach(() => {
22
+ jwks.start();
23
+ });
24
+
25
+ afterEach(async () => {
26
+ await jwks.stop();
27
+ });
28
+
29
+ it('should verify managed service account tokens', async () => {
30
+ const user = createTestUser({
31
+ subjectType: SubjectType.ManagedServiceAccount,
32
+ });
33
+ const token = jwks.token(user);
34
+
35
+ const result = await getAuthenticatedManagementSubject(token, authEndpoint);
36
+ expect(result).toEqual(user);
37
+ });
38
+ });
39
+
40
+ describe('getAuthenticatedManagementSubject method', () => {
41
+ const tenantId = '27aa1b27-3441-4115-84aa-1ed5f3072248';
42
+ const environmentId = '83bfce33-61b1-4ec5-93d5-ad40e4ed33c9';
43
+ const jwks = createJWKSMock(
44
+ authEndpoint,
45
+ `/${tenantId}/${environmentId}/.well-known/jwks.json`,
46
+ );
47
+
48
+ beforeEach(() => {
49
+ jwks.start();
50
+ });
51
+
52
+ afterEach(async () => {
53
+ await jwks.stop();
54
+ });
55
+
56
+ it('should verify tokens', async () => {
57
+ const user = createTestUser();
58
+ const token = jwks.token(user);
59
+ const config: AuthenticationConfig = {
60
+ authEndpoint,
61
+ tenantId,
62
+ environmentId,
63
+ };
64
+
65
+ const result = await getAuthenticatedManagementSubject(token, config);
66
+ expect(result).toEqual(user);
67
+ });
68
+
69
+ it('should handle token expiry', async () => {
70
+ const user = createTestUser({
71
+ exp: 0,
72
+ });
73
+ const token = jwks.token(user);
74
+ const config: AuthenticationConfig = {
75
+ authEndpoint,
76
+ tenantId,
77
+ environmentId,
78
+ };
79
+
80
+ await expect(
81
+ getAuthenticatedManagementSubject(token, config),
82
+ ).rejects.toThrow(TokenExpiredError);
83
+ });
84
+ });
85
+
86
+ describe('getEndUserApplication method', () => {
87
+ const tenantId = '27aa1b27-3441-4115-84aa-1ed5f3072248';
88
+ const environmentId = '83bfce33-61b1-4ec5-93d5-ad40e4ed33c9';
89
+ const applicationId = 'd2f708a9-8c71-4db7-9c09-a84147d2e1c5';
90
+
91
+ const jwks = createJWKSMock(
92
+ authEndpoint,
93
+ `/${tenantId}/${environmentId}/${applicationId}/.well-known/jwks.json`,
94
+ );
95
+
96
+ beforeEach(() => {
97
+ jwks.start();
98
+ });
99
+
100
+ afterEach(async () => {
101
+ await jwks.stop();
102
+ });
103
+ it('should verify an end-user application token', async () => {
104
+ const endUserApplication = createTestEndUserApplication();
105
+ const token = jwks.token(endUserApplication);
106
+ const config: AuthenticationConfig = {
107
+ authEndpoint,
108
+ tenantId,
109
+ environmentId,
110
+ };
111
+
112
+ const result = await getAuthenticatedEndUser(token, config);
113
+ expect(result).toEqual(endUserApplication);
114
+ });
115
+ });
116
+
117
+ describe('getAuthenticatedEndUser', () => {
118
+ const tenantId = '27aa1b27-3441-4115-84aa-1ed5f3072248';
119
+ const environmentId = '83bfce33-61b1-4ec5-93d5-ad40e4ed33c9';
120
+ const applicationId = '0a0857af-9d3a-4d39-96c9-f0f15fbaecdf';
121
+
122
+ const jwks = createJWKSMock(
123
+ authEndpoint,
124
+ `/${tenantId}/${environmentId}/${applicationId}/.well-known/jwks.json`,
125
+ );
126
+
127
+ beforeEach(() => {
128
+ jwks.start();
129
+ });
130
+
131
+ afterEach(async () => {
132
+ await jwks.stop();
133
+ });
134
+
135
+ it('should verify tokens', async () => {
136
+ const endUser = createTestUser({
137
+ applicationId,
138
+ subjectType: SubjectType.EndUserAccount,
139
+ iss: TOKEN_ISSUER_USER_SERVICE,
140
+ });
141
+ const token = jwks.token(endUser);
142
+
143
+ const config: AuthenticationConfig = {
144
+ authEndpoint,
145
+ tenantId,
146
+ environmentId,
147
+ };
148
+
149
+ const result = await getAuthenticatedEndUser(token, config);
150
+
151
+ expect(result).toEqual(endUser);
152
+ });
153
+
154
+ it('should handle token expiry', async () => {
155
+ const endUser = createTestUser({
156
+ exp: 0,
157
+ applicationId,
158
+ subjectType: SubjectType.EndUserAccount,
159
+ iss: TOKEN_ISSUER_USER_SERVICE,
160
+ });
161
+ const token = jwks.token(endUser);
162
+ const config: AuthenticationConfig = {
163
+ authEndpoint,
164
+ tenantId,
165
+ environmentId,
166
+ };
167
+
168
+ await expect(getAuthenticatedEndUser(token, config)).rejects.toThrow(
169
+ TokenExpiredError,
170
+ );
171
+ });
172
+
173
+ it('When a JWT with the property mosaic.end-user.accessToken is passed with the value having a valid end-user access token, it should be successfully verified', async () => {
174
+ // Arrange
175
+ const config: AuthenticationConfig = {
176
+ authEndpoint,
177
+ tenantId,
178
+ environmentId,
179
+ };
180
+ const endUser = createTestUser({
181
+ applicationId,
182
+ subjectType: SubjectType.EndUserAccount,
183
+ iss: TOKEN_ISSUER_USER_SERVICE,
184
+ });
185
+ const endUserJwt = jwks.token(endUser);
186
+ const tokenPayloadWithEmbeddedJwt = {
187
+ sub: '1234567890',
188
+ name: 'Jonas Khanwald',
189
+ iat: 1646631810,
190
+ exp: 2046635410,
191
+ [EMBEDDED_END_USER_TOKEN_KEY]: endUserJwt,
192
+ };
193
+ const embeddedJwt = jwks.token(tokenPayloadWithEmbeddedJwt);
194
+
195
+ // Act
196
+ const authenticatedEndUser = await getAuthenticatedEndUser(
197
+ embeddedJwt,
198
+ config,
199
+ );
200
+
201
+ // Assert
202
+ expect(authenticatedEndUser).toEqual(endUser);
203
+ });
204
+
205
+ it.each([
206
+ jwks.token({
207
+ sub: '1234567890',
208
+ name: 'John Doe',
209
+ iat: 1646631810,
210
+ exp: 2046635410,
211
+ }),
212
+ 'inavlid-token-that-is-not-even-a-jwt',
213
+ ])(
214
+ 'When a JWT with the property mosaic.end-user.accessToken is passed, but the JWT is not a valid token Mosaic End-User Token, an error is raised',
215
+ async (invalidEmbeddedJwt) => {
216
+ // Arrange
217
+ const config: AuthenticationConfig = {
218
+ authEndpoint,
219
+ tenantId,
220
+ environmentId,
221
+ };
222
+ const tokenPayloadWithEmbeddedJwt = {
223
+ sub: '1234567890',
224
+ name: 'Jonas Khanwald',
225
+ iat: 1646631810,
226
+ exp: 2046635410,
227
+ [EMBEDDED_END_USER_TOKEN_KEY]: invalidEmbeddedJwt,
228
+ };
229
+ const embeddedJwt = jwks.token(tokenPayloadWithEmbeddedJwt);
230
+
231
+ // Act and Assert
232
+ await expect(
233
+ getAuthenticatedEndUser(embeddedJwt, config),
234
+ ).rejects.toThrow(
235
+ 'Passed JWT is not a Mosaic End-User Token. Cannot be verified.',
236
+ );
237
+ },
238
+ );
239
+
240
+ it('When a JWT that is not an End-User Access Token is passed, an error is raised', async () => {
241
+ // Arrange
242
+ const config: AuthenticationConfig = {
243
+ authEndpoint,
244
+ tenantId,
245
+ environmentId,
246
+ };
247
+
248
+ const tokenPayloadWithEmbeddedJwt = {
249
+ sub: '1234567890',
250
+ name: 'Jonas Khanwald',
251
+ iat: 1646631810,
252
+ exp: 2046635410,
253
+ };
254
+ const embeddedJwt = jwks.token(tokenPayloadWithEmbeddedJwt);
255
+
256
+ // Act and Assert
257
+ await expect(getAuthenticatedEndUser(embeddedJwt, config)).rejects.toThrow(
258
+ 'Passed JWT is not a Mosaic End-User Token. Cannot be verified.',
259
+ );
260
+ });
261
+ });
@@ -0,0 +1,222 @@
1
+ import { isNullOrWhitespace } from '@axinom/mosaic-service-common';
2
+ import jwt from 'jsonwebtoken';
3
+ import jwks from 'jwks-rsa';
4
+ import { IdGuardError } from './id-guard-error';
5
+ import { IdGuardErrors } from './id-guard-errors';
6
+ import {
7
+ getJwtVerifyOptions,
8
+ TOKEN_ISSUER_ID_SERVICE,
9
+ TOKEN_ISSUER_USER_SERVICE,
10
+ } from './jwt-verify-options';
11
+ import { SubjectType } from './subject-type';
12
+ import {
13
+ AuthenticatedEndUser,
14
+ AuthenticatedEndUserApplication,
15
+ AuthenticatedManagementSubject,
16
+ AuthenticationConfig,
17
+ } from './types';
18
+
19
+ export const EMBEDDED_END_USER_TOKEN_KEY = 'mosaic.end-user.accessToken';
20
+
21
+ /**
22
+ * Parses a JWT token to produce an `AuthenticatedManagementSubject`.
23
+ * This function is intended to be used by any service which works with the Mosaic Management System.
24
+ *
25
+ * @param {string} token JWT token without `Bearer ` prefix
26
+ * @param {string | AuthenticationConfig} authParams This could be either a string containing the Auth Endpoint for the ID Service or an instance of `AuthenticationConfig`.
27
+ * @returns {Promise<AuthenticatedManagementSubject>} AuthenticatedManagementSubject
28
+ */
29
+ export const getAuthenticatedManagementSubject = async (
30
+ token: string,
31
+ authParams: string | AuthenticationConfig,
32
+ ): Promise<AuthenticatedManagementSubject> => {
33
+ let tenantId = '';
34
+ let environmentId = '';
35
+ let isManagedServiceAccount = false;
36
+ let jwksUri = '';
37
+
38
+ const decoded = jwt.decode(token) as AuthenticatedManagementSubject;
39
+ const issuer = decoded.iss;
40
+
41
+ // Tenant ID and Environment ID should be decoded from the token
42
+ tenantId = decoded.tenantId;
43
+ environmentId = decoded.environmentId;
44
+ isManagedServiceAccount =
45
+ decoded.subjectType === SubjectType.ManagedServiceAccount;
46
+
47
+ // If token is not issued by the ID Service, the jwks URI will not be set, and the verification will fail.
48
+ if (issuer === TOKEN_ISSUER_ID_SERVICE) {
49
+ if (typeof authParams === 'string') {
50
+ if (isManagedServiceAccount) {
51
+ jwksUri = new URL(`/.well-known/jwks.json`, authParams).href;
52
+ } else {
53
+ jwksUri = new URL(
54
+ `/${tenantId}/${environmentId}/.well-known/jwks.json`,
55
+ authParams,
56
+ ).href;
57
+ }
58
+ } else {
59
+ // TODO: Refactor this to support AuthenticationConfig with mandatory values.
60
+ if (
61
+ !isNullOrWhitespace(authParams.tenantId) &&
62
+ !isNullOrWhitespace(authParams.environmentId)
63
+ ) {
64
+ tenantId = authParams.tenantId;
65
+ environmentId = authParams.environmentId;
66
+ }
67
+
68
+ if (isManagedServiceAccount) {
69
+ jwksUri = new URL(`/.well-known/jwks.json`, authParams.authEndpoint)
70
+ .href;
71
+ } else {
72
+ jwksUri = new URL(
73
+ `/${tenantId}/${environmentId}/.well-known/jwks.json`,
74
+ authParams.authEndpoint,
75
+ ).href;
76
+ }
77
+ }
78
+ }
79
+
80
+ // Verify access token using JWKS
81
+ return (await verifyTokenAndGetAuthenticatedSubject(
82
+ token,
83
+ jwksUri,
84
+ 'MANAGEMENT',
85
+ )) as AuthenticatedManagementSubject;
86
+ };
87
+
88
+ /**
89
+ * Parses a JWT token to produce an `AuthenticatedEndUser` or an `AuthenticatedEndUserApplication`.
90
+ * This function is intended to be used by any service which works with End-User Applications.
91
+ *
92
+ * @param {string} token JWT token without `Bearer ` prefix.
93
+ * @param {string | AuthenticationConfig} authParams This could be either a string containing the Auth Endpoint for the User Service or an instance of `AuthenticationConfig`.
94
+ * @returns {Promise<AuthenticatedEndUser | AuthenticatedEndUserApplication>} AuthenticatedEndUser/AuthenticatedEndUserApplication
95
+ */
96
+ export const getAuthenticatedEndUser = async (
97
+ token: string,
98
+ authParams: string | AuthenticationConfig,
99
+ ): Promise<AuthenticatedEndUser | AuthenticatedEndUserApplication> => {
100
+ let tenantId = '';
101
+ let environmentId = '';
102
+ let jwksUri = '';
103
+ let endUserToken = '';
104
+
105
+ const decodedToken = jwt.decode(token) as Record<string, unknown>;
106
+
107
+ // Handle embedded end-user token.
108
+ if (decodedToken[EMBEDDED_END_USER_TOKEN_KEY] !== undefined) {
109
+ endUserToken = String(decodedToken[EMBEDDED_END_USER_TOKEN_KEY]);
110
+ } else {
111
+ endUserToken = token;
112
+ }
113
+
114
+ const decodedEndUserToken = jwt.decode(
115
+ endUserToken,
116
+ ) as AuthenticatedEndUserApplication;
117
+
118
+ // There can be a chance the token passed through `mosaic.end-user.accessToken` is not a valid JWT. (i.e. a simple string)
119
+ if (isNullOrWhitespace(decodedEndUserToken)) {
120
+ throw new IdGuardError(IdGuardErrors.JwtIsNotMosaicEndUserToken);
121
+ }
122
+ const issuer = decodedEndUserToken.iss;
123
+ tenantId = decodedEndUserToken.tenantId;
124
+ environmentId = decodedEndUserToken.environmentId;
125
+ const applicationId = decodedEndUserToken.applicationId;
126
+
127
+ // If token is not issued by the User Service, the jwks URI will not be set, and the verification will fail.
128
+ if (issuer === TOKEN_ISSUER_USER_SERVICE) {
129
+ if (typeof authParams === 'string') {
130
+ jwksUri = new URL(
131
+ `/${tenantId}/${environmentId}/${applicationId}/.well-known/jwks.json`,
132
+ authParams,
133
+ ).href;
134
+ } else {
135
+ // TODO: Refactor this to support AuthenticationConfig with mandatory values.
136
+ if (
137
+ !isNullOrWhitespace(authParams.tenantId) &&
138
+ !isNullOrWhitespace(authParams.environmentId)
139
+ ) {
140
+ tenantId = authParams.tenantId;
141
+ environmentId = authParams.environmentId;
142
+ }
143
+
144
+ jwksUri = new URL(
145
+ `/${tenantId}/${environmentId}/${applicationId}/.well-known/jwks.json`,
146
+ authParams.authEndpoint,
147
+ ).href;
148
+ }
149
+ }
150
+
151
+ if (decodedEndUserToken.subjectType === SubjectType.EndUserApplication) {
152
+ // Verify access token using JWKS
153
+ return (await verifyTokenAndGetAuthenticatedSubject(
154
+ endUserToken,
155
+ jwksUri,
156
+ 'END_USER_APPLICATION',
157
+ )) as AuthenticatedEndUserApplication;
158
+ } else if (decodedEndUserToken.subjectType === SubjectType.EndUserAccount) {
159
+ // Verify access token using JWKS
160
+ return (await verifyTokenAndGetAuthenticatedSubject(
161
+ endUserToken,
162
+ jwksUri,
163
+ 'END_USER',
164
+ )) as AuthenticatedEndUser;
165
+ } else {
166
+ throw new IdGuardError(IdGuardErrors.JwtIsNotMosaicEndUserToken);
167
+ }
168
+ };
169
+
170
+ const verifyTokenAndGetAuthenticatedSubject = async (
171
+ token: string,
172
+ jwksUri: string,
173
+ authType: 'MANAGEMENT' | 'END_USER' | 'END_USER_APPLICATION',
174
+ ): Promise<
175
+ | AuthenticatedManagementSubject
176
+ | AuthenticatedEndUser
177
+ | AuthenticatedEndUserApplication
178
+ > => {
179
+ return new Promise<
180
+ | AuthenticatedManagementSubject
181
+ | AuthenticatedEndUser
182
+ | AuthenticatedEndUserApplication
183
+ >((resolve, reject) => {
184
+ const jwksClient = jwks({
185
+ jwksUri,
186
+ cache: true,
187
+ cacheMaxAge: 1000 * 60 * 10, // 10 Minutes (same as access token lifetime)
188
+ cacheMaxEntries: 100,
189
+ });
190
+
191
+ const getPublicKey: jwt.GetPublicKeyOrSecret = (
192
+ header: jwt.JwtHeader,
193
+ callback: jwt.SigningKeyCallback,
194
+ ): void => {
195
+ jwksClient.getSigningKey(
196
+ header.kid ?? 'MISSING_KEY_ID_IN_JWT_HEADER',
197
+ (error: Error | null, key: jwks.SigningKey) => {
198
+ if (error) {
199
+ reject(error);
200
+ return;
201
+ }
202
+ callback(null, key.getPublicKey());
203
+ },
204
+ );
205
+ };
206
+
207
+ jwt.verify(token, getPublicKey, getJwtVerifyOptions(), (error, decoded) => {
208
+ if (error) {
209
+ reject(error);
210
+ return;
211
+ }
212
+
213
+ if (authType === 'MANAGEMENT') {
214
+ resolve(decoded as AuthenticatedManagementSubject);
215
+ } else if (authType === 'END_USER') {
216
+ resolve(decoded as AuthenticatedEndUser);
217
+ } else {
218
+ resolve(decoded as AuthenticatedEndUserApplication);
219
+ }
220
+ });
221
+ });
222
+ };